diff --git a/docs/locales/uk/advanced/actions.md b/docs/locales/uk/advanced/actions.md new file mode 100644 index 000000000..22a93fa1f --- /dev/null +++ b/docs/locales/uk/advanced/actions.md @@ -0,0 +1,1242 @@ +--- +sidebarLabel: "Дії та Блінки" +title: "Дії та Блінки" +seoTitle: "Дії та Блінки" +description: + "Дії Solana — це API, які повертають транзакції для попереднього перегляду і + підпису користувачами. Посилання на блокчейн — або блінки — перетворюють дії в + зручні, багаті на метадані посилання для спільного використання." +altRoutes: + - /docs/actions + - /docs/blinks + - /docs/advanced/blinks +--- + +[Дії Solana](#actions) — це API, які відповідають специфікації і повертають +транзакції в блокчейні Solana для попереднього перегляду, підпису та відправки. +Вони можуть використовуватися в різних контекстах, таких як QR-коди, кнопки, +віджети та вебсайти. Дії дозволяють розробникам легко інтегрувати функціонал +екосистеми Solana у свій додаток, дозволяючи виконувати блокчейн-транзакції без +необхідності переходу на інші сторінки або додатки. + +[Посилання на блокчейн](#blinks) — або блінки — перетворюють будь-яку дію Solana +в зручне посилання, багате метаданими. Блінки дозволяють клієнтам, які +підтримують їх, (таким як гаманці або боти) відображати додаткові функціональні +можливості. Наприклад, на вебсайті блінк може негайно відкрити попередній +перегляд транзакції у гаманці, а в Discord бот може перетворити блінк на +інтерактивні кнопки. Це забезпечує взаємодію з блокчейном на будь-якій +платформі, що підтримує URL. + +## Початок роботи + +Щоб швидко почати створювати власні дії Solana: + +```shell +npm install @solana/actions +``` + +- встановіть [Solana Actions SDK](https://www.npmjs.com/package/@solana/actions) + у вашому додатку +- створіть API-ендпойнт для [GET-запиту](#get-request), який повертає метадані + про вашу дію +- створіть API-ендпойнт для [POST-запиту](#post-request), який повертає + транзакцію для підпису користувачем + +> Перегляньте цей відеоурок про +> [створення дії Solana](https://www.youtube.com/watch?v=kCht01Ycif0) за +> допомогою `@solana/actions` SDK. +> +> Ви також можете знайти +> [вихідний код дії](https://github.com/solana-developers/solana-actions/blob/main/examples/next-js/src/app/api/actions/transfer-sol/route.ts), +> яка виконує нативний переказ SOL, а також інші приклади дій у +> [цьому репозиторії](https://github.com/solana-developers/solana-actions/tree/main/examples). + +Під час розгортання власних дій Solana у продакшн: + +- переконайтеся, що ваш додаток має дійсний файл [actions.json](#actionsjson) у + корені вашого домену +- переконайтеся, що ваш додаток відповідає + [необхідним заголовкам CORS](#options-response) для всіх ендпойнтів дій, + включаючи файл `actions.json` +- тестуйте та налагоджуйте свої блінки/дії за допомогою + [Blinks Inspector](https://www.blinks.xyz/inspector) + +Якщо ви шукаєте натхнення для створення дій та блінків, перегляньте +[Awesome Blinks](https://github.com/solana-developers/awesome-blinks) — +репозиторій із прикладами створених спільнотою блінків та +[ідеями для нових](https://github.com/solana-developers/awesome-blinks/discussions/categories/ideas-for-blinks). + +## Дії + +Специфікація дій Solana використовує набір стандартних API для передачі +транзакцій (та, зрештою, повідомлень) для підпису безпосередньо користувачам. Ці +API доступні за публічними URL, які можуть взаємодіяти з будь-якими клієнтами. + +> Дії можна уявити як API-ендпойнт, який повертає метадані та об'єкт для підпису +> користувачем (транзакцію або повідомлення для аутентифікації) за допомогою їх +> блокчейн-гаманця. + +API дій складається з простих `GET` і `POST` запитів до URL-ендпойнтів дій та +обробки відповідей, які відповідають інтерфейсу дій. + +1. [GET-запит](#get-request) повертає метадані, які надають клієнту інформацію + про доступні дії за цим URL, а також список пов’язаних дій (за бажанням). +2. [POST-запит](#post-request) повертає транзакцію або повідомлення для підпису, + які клієнт відображає в гаманці користувача для підпису та виконання у + блокчейні або іншому офчейн-сервісі. + +### Виконання дії та життєвий цикл + +На практиці взаємодія з діями нагадує роботу зі стандартним REST API: + +- клієнт надсилає початковий `GET`-запит до URL дії для отримання метаданих про + доступні дії +- ендпойнт повертає відповідь, яка включає метадані (наприклад, заголовок + програми та іконку) і перелік доступних дій +- клієнтський додаток (наприклад, мобільний гаманець, чат-бот або вебсайт) + відображає інтерфейс для виконання однієї з дій +- після вибору дії користувачем (натискання кнопки) клієнт надсилає `POST`-запит + до ендпойнта, щоб отримати транзакцію для підпису +- гаманець допомагає користувачеві підписати транзакцію і зрештою надсилає її в + блокчейн для підтвердження + +![Життєвий цикл виконання дій Solana](/public/assets/docs/action-execution-and-lifecycle.png) + +Під час отримання транзакцій із URL дій клієнти повинні обробляти надсилання цих +транзакцій у блокчейн і управляти їхнім станом. + +Дії також підтримують певний рівень недійсності перед виконанням. `GET`- та +`POST`-запити можуть повертати метадані, які вказують, чи можливо виконати дію +(наприклад, через поле `disabled`). + +Наприклад, якщо ендпойнт дії підтримує голосування за пропозицію DAO, термін +голосування за якою закінчився, початковий [GET-запит](#get-request) може +повернути повідомлення про помилку "Цю пропозицію більше не можна обговорювати", +а кнопки "Проголосувати за" та "Проголосувати проти" — як "вимкнені". + +## Блінки + +Блінки (посилання на блокчейн) — це клієнтські програми, які аналізують API дій +і створюють інтерфейси користувача для взаємодії з діями та їх виконання. + +Клієнтські програми, що підтримують блінки, виявляють URL, сумісні з діями, +аналізують їх і дозволяють користувачам взаємодіяти з ними у стандартизованих +інтерфейсах. + +> Будь-яка клієнтська програма, яка повністю аналізує API дій для створення +> повноцінного інтерфейсу, є _блінком_. Отже, не всі клієнти, які використовують +> API дій, є блінками. + +### Специфікація URL блінків + +URL блінка описує клієнтську програму, яка дозволяє користувачеві завершити +повний [життєвий цикл виконання дії](#action-execution-and-lifecycle), включаючи +підписання у гаманці. + +```text +https://example.domain/?action= +``` + +Для того, щоб будь-яка клієнтська програма могла стати блінком: + +- URL блінка повинен містити параметр запиту `action`, значення якого має бути + [URL-кодованим](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent) + [URL дії](#url-scheme). Це значення має бути закодоване, щоб уникнути + конфліктів з іншими параметрами протоколу. + +- Клієнтська програма повинна + [декодувати URL](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent) + параметр запиту `action` і аналізувати наданий посилання API дій (див. + [Схему URL дії](#url-scheme)). + +- Клієнт повинен відобразити багатий інтерфейс користувача, який дозволяє + завершити повний + [життєвий цикл виконання дії](#action-execution-and-lifecycle), включаючи + підписання у гаманці. + +> Не всі клієнтські програми-блінки (наприклад, вебсайти або децентралізовані +> додатки) підтримуватимуть усі дії. Розробники додатків можуть обирати, які дії +> вони хочуть підтримувати у своїх інтерфейсах блінків. + +Наступний приклад демонструє дійсний URL блінка зі значенням параметра `action` +`solana-action:https://actions.alice.com/donate`, яке закодовано у форматі URL: + +```text +https://example.domain/?action=solana-action%3Ahttps%3A%2F%2Factions.alice.com%2Fdonate +``` + +### Виявлення дій через блінки + +Блінки можуть бути пов’язані з діями щонайменше трьома способами: + +1. Поширення явного URL дії: `solana-action:https://actions.alice.com/donate` + + У цьому випадку лише клієнти, які підтримують блінки, можуть відобразити + блінк. Не буде доступного попереднього перегляду посилання або сайту, який + можна відвідати поза клієнтами, що не підтримують блінки. + +2. Поширення посилання на вебсайт, пов’язаний із API дій через файл + [`actions.json`](#actionsjson) у кореневій директорії домену вебсайту. + + Наприклад, `https://alice.com/actions.json` зіставляє + `https://alice.com/donate`, URL вебсайту, на якому користувачі можуть зробити + пожертву для Alice, з API URL `https://actions.alice.com/donate`, на якому + хостяться дії для пожертвування Alice. + +3. Вбудовування URL дії у "перехідний" URL сайту, який розуміє, як аналізувати + дії. + + ```text + https://example.domain/?action= + ``` + +Клієнти, які підтримують блінки, повинні мати можливість працювати з будь-яким +із зазначених форматів і правильно відображати інтерфейс для виконання дії +безпосередньо в клієнті. + +Для клієнтів, які не підтримують блінки, повинен бути доступний основний +вебсайт, що робить браузер універсальним варіантом резервного доступу. + +Якщо користувач натискає на будь-яку область клієнта, яка не є кнопкою дії або +полем для введення тексту, він повинен бути перенаправлений на основний сайт. + +### Тестування та перевірка блінків + +Хоча Solana Actions і блінки є протоколом/специфікацією без дозволів, клієнтські +додатки та гаманці повинні забезпечити можливість користувачам підписувати +транзакцію. + +> Використовуйте інструмент [Blinks Inspector](https://www.blinks.xyz/inspector) +> для перевірки, налагодження та тестування ваших блінків і дій безпосередньо в +> браузері. Ви можете переглядати GET і POST відповіді, заголовки та тестувати +> всі введення для кожної з ваших пов'язаних дій. + +Кожен клієнтський додаток або гаманець може мати різні вимоги щодо того, які +ендпойнти дій будуть автоматично розгортатися й негайно відображатися +користувачам на платформах соціальних мереж. + +Наприклад, деякі клієнти можуть працювати за підходом "список дозволених" і +вимагати верифікації перед розгортанням дії для користувачів, як це робить +реєстр дій Dialect (докладно описано нижче). + +Усі блінки все одно будуть відображатися й дозволять підписання на сайті Dialect +[dial.to](https://dial.to), де їхній статус у реєстрі буде показаний у блінку. + +### Реєстр дій Dialect + +Як загальне благо для екосистеми Solana, [Dialect](https://dialect.to) підтримує +публічний реєстр — разом із допомогою Solana Foundation та інших членів +спільноти — для посилань на блокчейн, які попередньо перевірені й походять із +відомих джерел. На момент запуску лише дії, зареєстровані в реєстрі Dialect, +будуть автоматично розгортатися у Twitter, коли їх публікують. + +Клієнтські програми та гаманці можуть вільно використовувати цей публічний +реєстр або інші рішення, щоб забезпечити безпеку користувачів. Якщо посилання на +блокчейн не верифіковане через реєстр Dialect, воно не оброблятиметься клієнтом +блінків і буде відображатися як звичайне URL. + +Розробники можуть подати заявку на верифікацію у Dialect тут: +[dial.to/register](https://dial.to/register) + +## Специфікація + +Специфікація Solana Actions складається з ключових розділів, які є частиною +процесу взаємодії запит/відповідь: + +- Схема URL [Solana Action](#url-scheme), яка надає URL дії +- [OPTIONS-відповідь](#options-response) на URL дії для відповідності вимогам + CORS +- [GET-запит](#get-request) до URL дії +- [GET-відповідь](#get-response) із сервера +- [POST-запит](#post-request) до URL дії +- [POST-відповідь](#post-response) із сервера + +Кожен із цих запитів надсилається _клієнтом дій_ (наприклад, гаманець, +розширення для браузера, децентралізований додаток, вебсайт тощо) для збору +специфічних метаданих для багатого інтерфейсу користувача та забезпечення вводу +користувачем до API дій. + +Кожна з відповідей створюється додатком (наприклад, вебсайтом, серверним +додатком тощо) і повертається _клієнту дій_. Зрештою, це забезпечує транзакцію +або повідомлення для підпису гаманцем, щоб користувач міг підтвердити, підписати +та надіслати їх до блокчейну. + +> Типи та інтерфейси, описані в цьому файлі readme, часто спрощені для +> полегшення читання. +> +> Для кращої безпеки типів і покращеного досвіду розробників пакет +> `@solana/actions-spec` містить більш складні визначення типів. Ви можете +> знайти +> [вихідний код тут](https://github.com/solana-developers/solana-actions/blob/main/packages/actions-spec/index.d.ts). + +### Схема URL + +URL дії Solana описує інтерактивний запит на підписання транзакції або +повідомлення в Solana за допомогою протоколу `solana-action`. + +Запит є інтерактивним, оскільки параметри в URL використовуються клієнтом для +надсилання серії стандартизованих HTTP-запитів для складання транзакції або +повідомлення для підписання користувачем у його гаманці. + +```text +solana-action: +``` + +- Єдине поле `link` обов’язкове як шлях. Значення повинно бути + [URL-кодованим](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent) + абсолютним HTTPS URL. + +- Якщо URL містить параметри запиту, він повинен бути закодований у форматі URL. + Це допомагає уникнути конфліктів із будь-якими параметрами протоколу дій, які + можуть бути додані через специфікацію протоколу. + +- Якщо URL не містить параметрів запиту, він не повинен бути закодованим у + форматі URL. Це забезпечує коротший URL і менш щільний QR-код. + +У будь-якому випадку клієнти повинні +[декодувати URL](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent) +значення. Це не матиме жодного ефекту, якщо значення вже не було закодовано. +Якщо декодоване значення не є абсолютним HTTPS URL, гаманець повинен відхилити +його як **пошкоджене**. + +### OPTIONS-відповідь + +Для забезпечення крос-доменного доступу (CORS) у клієнтах дій (включаючи +блінки), усі ендпойнти дій повинні відповідати на HTTP-запити методу `OPTIONS` з +дійсними заголовками, які дозволять клієнтам проходити CORS-перевірки для всіх +подальших запитів із їхнього домену. + +Клієнт дій може виконувати +"[префлайт-запити](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#preflighted_requests)" +до ендпойнта URL дії, щоб перевірити, чи пройде наступний GET-запит до цього URL +всі CORS-перевірки. Ці перевірки виконуються за допомогою HTTP-методу `OPTIONS` +і повинні відповідати з усіма необхідними HTTP-заголовками, які дозволяють +клієнтам дій (наприклад, блінкам) правильно виконувати всі подальші запити. + +Мінімальний набір обов’язкових HTTP-заголовків: + +- `Access-Control-Allow-Origin` зі значенням `*` + - забезпечує можливість усім клієнтам дій безпечно проходити CORS-перевірки + для виконання всіх необхідних запитів. +- `Access-Control-Allow-Methods` зі значенням `GET,POST,PUT,OPTIONS` + - забезпечує підтримку всіх необхідних HTTP-методів запитів для дій. +- `Access-Control-Allow-Headers` з мінімальним значенням + `Content-Type, Authorization, Content-Encoding, Accept-Encoding`. + +Для спрощення розробникам слід розглянути можливість повернення однакової +відповіді та заголовків на запити `OPTIONS`, що і для їхнього +[GET-відповіді](#get-response). + + + +Відповідь файлу `actions.json` також повинна повертати дійсні заголовки +крос-доменного доступу для запитів `GET` і `OPTIONS`, зокрема заголовок +`Access-Control-Allow-Origin` зі значенням `*`. + +Докладніше дивіться у розділі [actions.json](#actionsjson). + + + +### GET-запит + +Клієнт дій (наприклад, гаманець, розширення браузера тощо) повинен надсилати +HTTP `GET` JSON-запит до URL-ендпойнта дії. + +- Запит не повинен ідентифікувати гаманець або користувача. +- Клієнт повинен виконувати запит із заголовком + [`Accept-Encoding`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding). +- Клієнт повинен відображати домен URL під час виконання запиту. + +### GET-відповідь + +URL-ендпойнт дії (наприклад, додаток або серверний бекенд) повинен відповідати +HTTP `OK` JSON-відповіддю (з дійсним вмістом у тілі) або відповідною помилкою +HTTP. + +- Клієнт повинен обробляти HTTP + [помилки клієнта](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses), + [помилки сервера](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#server_error_responses) + та + [редиректи](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#redirection_messages). +- Ендпойнт повинен відповідати із заголовком + [`Content-Encoding`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding) + для HTTP-компресії. +- Ендпойнт повинен відповідати із заголовком + [`Content-Type`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) + зі значенням `application/json`. + +- Клієнт не повинен кешувати відповідь, окрім випадків, коли це вказано у + [HTTP-заголовках кешування](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#controlling_caching). +- Клієнт повинен відображати `title` і рендерити іконку `icon` для користувача. + +Помилкові відповіді (тобто статуси HTTP 4xx та 5xx) повинні повертати JSON-тіло +відповіді, яке відповідає `ActionError`, щоб представити користувачам корисне +повідомлення про помилку. Дивіться [Помилки дій](#action-errors). + +#### Тіло GET-відповіді + +`GET`-відповідь зі статусом HTTP `OK` повинна включати тіло з вмістом, що +відповідає специфікації інтерфейсу: + +```ts filename="ActionGetResponse" +export type ActionType = "action" | "completed"; + +export type ActionGetResponse = Action<"action">; + +export interface Action { + /** type of Action to present to the user */ + type: T; + /** image url that represents the source of the action request */ + icon: string; + /** describes the source of the action request */ + title: string; + /** brief summary of the action to be performed */ + description: string; + /** button text rendered to the user */ + label: string; + /** UI state for the button being rendered to the user */ + disabled?: boolean; + links?: { + /** list of related Actions a user could perform */ + actions: LinkedAction[]; + }; + /** non-fatal error message to be displayed to the user */ + error?: ActionError; +} +``` + +- `type` - Тип дії, що надається користувачеві. За замовчуванням встановлено + значення `action`. Початковий `ActionGetResponse` повинен мати тип `action`. + + - `action` - Стандартна дія, яка дозволяє користувачеві взаємодіяти з + будь-якими `LinkedActions`. + - `completed` - Використовується для позначення стану "завершено" у ланцюжку + дій. + +- `icon` - Значення має бути абсолютним HTTP або HTTPS URL іконки. Файл повинен + бути формату SVG, PNG або WebP, інакше клієнт/гаманець повинен відхилити його + як **пошкоджений**. + +- `title` - Значення має бути рядком UTF-8, що представляє джерело запиту дії. + Наприклад, це може бути назва бренду, магазину, програми або особи, яка робить + запит. + +- `description` - Значення має бути рядком UTF-8, що надає інформацію про дію. + Опис повинен бути відображений користувачеві. + +- `label` - Значення має бути рядком UTF-8, який буде відображено на кнопці для + натискання користувачем. Усі мітки не повинні перевищувати 5 слів і повинні + починатися з дієслова, щоб закріпити дію, яку ви хочете, щоб користувач + виконав. Наприклад, "Mint NFT", "Vote Yes" або "Stake 1 SOL". + +- `disabled` - Значення має бути логічним (boolean), щоб представляти стан + вимкнення кнопки (яка відображає рядок `label`). Якщо значення не надано, + `disabled` має за замовчуванням бути `false` (тобто увімкнено). Наприклад, + якщо кінцева точка дії використовується для голосування, яке вже закрите, + встановіть `disabled=true`, а мітка може бути "Vote Closed". + +- `error` - Необов'язковий індикатор помилки для нефатальних помилок. Якщо + присутній, клієнт повинен відобразити це користувачеві. Якщо встановлено, це + не повинно заважати клієнту інтерпретувати дію або відображати її + користувачеві (див. [Помилки дій](#action-errors)). Наприклад, помилка може + використовуватися разом із `disabled`, щоб показати причину, як-от + бізнес-обмеження, авторизація, стан або помилка зовнішнього ресурсу. + +- `links.actions` - Необов'язковий масив пов'язаних дій для кінцевої точки. + Користувачам повинен бути відображений інтерфейс для кожної зі вказаних дій, і + очікується, що вони виконають лише одну. Наприклад, кінцева точка дії для + голосування в управлінні DAO може повернути три варіанти для користувача: + "Vote Yes", "Vote No" і "Abstain from Vote". + + - Якщо `links.actions` не надано, клієнт повинен відобразити одну кнопку, + використовуючи кореневий рядок `label`, і виконати POST-запит до тієї самої + кінцевої точки URL дії, що й початковий GET-запит. + + - Якщо будь-які `links.actions` надані, клієнт повинен відображати лише кнопки + та поля введення на основі елементів, перелічених у полі `links.actions`. + Клієнт не повинен відображати кнопку для вмісту кореневого `label`. + +```ts filename="LinkedAction" +export interface LinkedAction { + /** URL endpoint for an action */ + href: string; + /** button text rendered to the user */ + label: string; + /** + * Parameters to accept user input within an action + * @see {ActionParameter} + * @see {ActionParameterSelectable} + */ + parameters?: Array; +} +``` + +`ActionParameter` дозволяє визначити, яке саме введення API дій запитує у +користувача: + +```ts filename="ActionParameter" +/** + * Parameter to accept user input within an action + * note: for ease of reading, this is a simplified type of the actual + */ +export interface ActionParameter { + /** input field type */ + type?: ActionParameterType; + /** parameter name in url */ + name: string; + /** placeholder text for the user input field */ + label?: string; + /** declare if this field is required (defaults to `false`) */ + required?: boolean; + /** regular expression pattern to validate user input client side */ + pattern?: string; + /** human-readable description of the `type` and/or `pattern`, represents a caption and error, if value doesn't match */ + patternDescription?: string; + /** the minimum value allowed based on the `type` */ + min?: string | number; + /** the maximum value allowed based on the `type` */ + max?: string | number; +} +``` + +`pattern` повинен бути рядком, еквівалентним дійсному регулярному виразу. Цей +регулярний вираз має використовуватися клієнтами-блінками для перевірки введення +користувача перед виконанням POST-запиту. Якщо `pattern` не є дійсним регулярним +виразом, клієнт повинен його ігнорувати. + +`patternDescription` — це опис, зрозумілий для людини, який пояснює очікуване +введення користувача. Якщо надано `pattern`, то `patternDescription` також +обов’язково має бути надано. + +Значення `min` та `max` дозволяють встановити нижню та/або верхню межу введення, +запитуваного у користувача (наприклад, мінімальне/максимальне число або +мінімальну/максимальну довжину рядка). Вони повинні використовуватися для +клієнтської валідації. Для типів введення `date` або `datetime-local` ці +значення мають бути рядками, що представляють дати. Для інших типів введення на +основі рядків значення повинні бути числами, що представляють їх +мінімальну/максимальну довжину символів. + +Якщо введене значення користувача не відповідає `pattern`, користувач має +отримати повідомлення про помилку на стороні клієнта, що вказує на недійсність +поля введення, і відображати рядок `patternDescription`. + +Поле `type` дозволяє API дій визначати більш конкретні поля введення +користувача, забезпечуючи кращу валідацію на стороні клієнта та покращуючи +користувацький досвід. У багатьох випадках цей тип буде подібний до стандартного +[елемента введення HTML](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). + +Тип `ActionParameterType` можна спростити до такого формату: + +```ts filename="ActionParameterType" +/** + * Input field type to present to the user + * @default `text` + */ +export type ActionParameterType = + | "text" + | "email" + | "url" + | "number" + | "date" + | "datetime-local" + | "checkbox" + | "radio" + | "textarea" + | "select"; +``` + +Кожне зі значень `type` зазвичай має відповідати полю введення користувача, яке +нагадує стандартний HTML-елемент `input` відповідного типу (наприклад, +``), щоб забезпечити кращу валідацію на стороні клієнта та +покращити користувацький досвід: + +- `text` - еквівалент HTML + [елемента введення типу "text"](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/text) +- `email` - еквівалент HTML + [елемента введення типу "email"](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/email) +- `url` - еквівалент HTML + [елемента введення типу "url"](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/url) +- `number` - еквівалент HTML + [елемента введення типу "number"](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number) +- `date` - еквівалент HTML + [елемента введення типу "date"](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date) +- `datetime-local` - еквівалент HTML + [елемента введення типу "datetime-local"](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/datetime-local) +- `checkbox` - еквівалент групи стандартних HTML + [елементів введення типу "checkbox"](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox). + API дій має повертати `options`, як описано нижче. Користувач повинен мати + змогу вибрати кілька запропонованих варіантів. +- `radio` - еквівалент групи стандартних HTML + [елементів введення типу "radio"](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/radio). + API дій має повертати `options`, як описано нижче. Користувач повинен мати + змогу вибрати лише один із запропонованих варіантів. +- Інші еквіваленти HTML-типів введення, не зазначені вище (`hidden`, `button`, + `submit`, `file` тощо), наразі не підтримуються. + +Окрім елементів, схожих на HTML-типи введення, також підтримуються наступні +елементи введення користувача: + +- `textarea` - еквівалент HTML + [елемента "textarea"](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea), + що дозволяє користувачеві вводити багаторядковий текст. +- `select` - еквівалент HTML + [елемента "select"](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select), + що надає користувачеві досвід вибору з випадаючого списку. API дій має + повертати `options`, як описано нижче. + +Коли `type` встановлено як `select`, `checkbox` або `radio`, API дій має +включати масив `options`, кожен із яких надає `label` та `value` принаймні. +Кожна опція також може мати значення `selected`, яке інформує клієнт-блінк, яка +опція має бути обрана за замовчуванням для користувача (див. відмінності для +`checkbox` і `radio`). + +Цей `ActionParameterSelectable` можна спростити до такого визначення типу: + +```ts filename="ActionParameterSelectable" +/** + * note: for ease of reading, this is a simplified type of the actual + */ +interface ActionParameterSelectable extends ActionParameter { + options: Array<{ + /** displayed UI label of this selectable option */ + label: string; + /** value of this selectable option */ + value: string; + /** whether or not this option should be selected by default */ + selected?: boolean; + }>; +} +``` + +Якщо `type` не встановлено або задано невідоме/непідтримуване значення, +клієнти-блінки мають за замовчуванням використовувати `text` і відображати +просте текстове поле введення. + +API дій все одно відповідає за валідацію та санітизацію всіх даних, отриманих +від параметрів введення користувача, забезпечуючи виконання всіх обов’язкових +("required") полів введення за необхідності. + +Для платформ, які не базуються на HTML/веб (наприклад, для нативних мобільних +додатків), слід використовувати еквівалентні нативні компоненти введення, щоб +забезпечити аналогічний досвід та валідацію на стороні клієнта, як описано для +HTML/веб. + +#### Приклад відповіді на GET-запит + +Наступний приклад відповіді забезпечує єдину "кореневу" дію, яка очікує, що +користувачеві буде представлена одна кнопка з міткою "Отримати токен доступу": + +```json +{ + "title": "HackerHouse Events", + "icon": "", + "description": "Claim your Hackerhouse access token.", + "label": "Claim Access Token" // button text +} +``` + +Наступний приклад відповіді забезпечує 3 пов’язані посилання на дії, що +дозволяють користувачеві натиснути одну з трьох кнопок для голосування за +пропозицію DAO: + +```json +{ + "title": "Realms DAO Platform", + "icon": "", + "description": "Vote on DAO governance proposals #1234.", + "label": "Vote", + "links": { + "actions": [ + { + "label": "Vote Yes", // button text + "href": "/api/proposal/1234/vote?choice=yes" + }, + { + "label": "Vote No", // button text + "href": "/api/proposal/1234/vote?choice=no" + }, + { + "label": "Abstain from Vote", // button text + "href": "/api/proposal/1234/vote?choice=abstain" + } + ] + } +} +``` + +#### Приклад відповіді на GET-запит з параметрами + +Наступні приклади відповіді демонструють, як приймати текстове введення від +користувача (через `parameters`) і включати це введення у кінцеву кінцеву точку +запиту `POST` (через поле `href` у `LinkedAction`): + +Наступний приклад відповіді забезпечує користувачеві 3 пов’язані дії для +стейкінгу SOL: кнопку з міткою "Stake 1 SOL", іншу кнопку з міткою "Stake 5 SOL" +та текстове поле введення, яке дозволяє користувачеві ввести конкретне значення +"amount", що буде надіслано до API дій: + +```json +{ + "title": "Stake-o-matic", + "icon": "", + "description": "Stake SOL to help secure the Solana network.", + "label": "Stake SOL", // not displayed since `links.actions` are provided + "links": { + "actions": [ + { + "label": "Stake 1 SOL", // button text + "href": "/api/stake?amount=1" + // no `parameters` therefore not a text input field + }, + { + "label": "Stake 5 SOL", // button text + "href": "/api/stake?amount=5" + // no `parameters` therefore not a text input field + }, + { + "label": "Stake", // button text + "href": "/api/stake?amount={amount}", + "parameters": [ + { + "name": "amount", // field name + "label": "SOL amount" // text input placeholder + } + ] + } + ] + } +} +``` + +Наступний приклад відповіді забезпечує одне поле введення для користувача, щоб +ввести `amount`, яке буде надіслано з запитом `POST` (може бути використано як +параметр запиту або як підшлях): + +```json +{ + "icon": "", + "label": "Donate SOL", + "title": "Donate to GoodCause Charity", + "description": "Help support this charity by donating SOL.", + "links": { + "actions": [ + { + "label": "Donate", // button text + "href": "/api/donate/{amount}", // or /api/donate?amount={amount} + "parameters": [ + // {amount} input field + { + "name": "amount", // input field name + "label": "SOL amount" // text input placeholder + } + ] + } + ] + } +} +``` + +### POST Запит + +Наступний приклад відповіді забезпечує одне поле введення для користувача, щоб +ввести `amount`, яке буде надіслано з запитом `POST` (може бути використано як +параметр запиту або як підшлях): + +```json +{ + "account": "" +} +``` + +- `account` - Значення повинно бути відкритим ключем облікового запису у форматі + base58, який може підписувати транзакцію. + +Клієнт має виконати запит із заголовком +[Accept-Encoding](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding), +а застосунок може відповісти заголовком +[Content-Encoding](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding) +для HTTP-компресії. + +Клієнт повинен відобразити домен URL дії під час виконання запиту. Якщо був +виконаний `GET`-запит, клієнт також повинен відобразити `title` та відрендерити +зображення `icon` з відповіді GET. + +### Відповідь на POST-запит + +Кінцева точка `POST` для дії повинна відповідати HTTP-відповіддю `OK` у форматі +JSON (з дійсним тілом відповіді) або відповідною HTTP-помилкою. + +- Клієнт повинен обробляти + [помилки клієнта](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses), + [помилки сервера](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#server_error_responses), + та + [відповіді-перенаправлення](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#redirection_messages). +- Кінцева точка повинна відповідати з заголовком + [`Content-Type`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) + значенням `application/json`. + +Помилкові відповіді (тобто HTTP-коди стану 4xx і 5xx) повинні повертати +JSON-відповідь, що відповідає структурі `ActionError`, для відображення +корисного повідомлення про помилку користувачам. Див. +[Помилки дій](#action-errors). + +#### Тіло відповіді на POST-запит + +Відповідь `POST` з HTTP-відповіддю `OK` у форматі JSON повинна включати тіло +відповіді наступного вигляду: + +```ts filename="ActionPostResponse" +/** + * Response body payload returned from the Action POST Request + */ +export interface ActionPostResponse { + /** base64 encoded serialized transaction */ + transaction: string; + /** describes the nature of the transaction */ + message?: string; + links?: { + /** + * The next action in a successive chain of actions to be obtained after + * the previous was successful. + */ + next: NextActionLink; + }; +} +``` + +- `transaction` - Значення повинно бути серіалізованою транзакцією, закодованою + в base64 + ([документація](https://solana-labs.github.io/solana-web3.js/v1.x/classes/Transaction.html#serialize)). + Клієнт повинен декодувати транзакцію з base64 і + [десеріалізувати її](https://solana-labs.github.io/solana-web3.js/v1.x/classes/Transaction.html#from). + +- `message` - Значення повинно бути рядком у форматі UTF-8, який описує суть + транзакції, включеної у відповідь. Клієнт повинен відобразити це значення + користувачу. Наприклад, це може бути назва товару, який купується, застосована + знижка, або подяка. + +- `links.next` - Необов'язкове значення, яке використовується для "зчеплення" + кількох дій у послідовності. Після підтвердження включеної `transaction` у + блокчейні клієнт може отримати та відобразити наступну дію. Дивіться + [Зчеплення дій](#action-chaining) для отримання додаткової інформації. + +- Клієнт та застосунок повинні дозволяти додаткові поля у тілі запиту та + відповіді, які можуть бути додані у майбутніх оновленнях специфікацій. + +> Застосунок може відповідати частково або повністю підписаною транзакцією. +> Клієнт та гаманець повинні перевіряти транзакцію як **ненадійну**. + +#### Відповідь POST - Транзакція + +Якщо у транзакції +[`signatures`](https://solana-labs.github.io/solana-web3.js/v1.x/classes/Transaction.html#signatures) +відсутні або транзакція ще не підписана частково: + +- Клієнт повинен ігнорувати + [`feePayer`](https://solana-labs.github.io/solana-web3.js/v1.x/classes/Transaction.html#feePayer) + у транзакції та встановити `feePayer` як `account` з запиту. +- Клієнт повинен ігнорувати + [`recentBlockhash`](https://solana-labs.github.io/solana-web3.js/v1.x/classes/Transaction.html#recentBlockhash) + у транзакції та встановити `recentBlockhash` на + [останній blockhash](https://solana-labs.github.io/solana-web3.js/v1.x/classes/Connection.html#getLatestBlockhash). +- Клієнт повинен серіалізувати та десеріалізувати транзакцію перед її + підписанням. Це забезпечує послідовний порядок ключів облікових записів як + рішення для + [цієї проблеми](https://github.com/solana-labs/solana/issues/21722). + +Якщо транзакція вже частково підписана: + +- Клієнт не повинен змінювати + [`feePayer`](https://solana-labs.github.io/solana-web3.js/v1.x/classes/Transaction.html#feePayer) + або + [`recentBlockhash`](https://solana-labs.github.io/solana-web3.js/v1.x/classes/Transaction.html#recentBlockhash), + оскільки це зробить існуючі підписи недійсними. +- Клієнт повинен перевірити існуючі підписи, і якщо будь-який з них недійсний, + клієнт повинен відхилити транзакцію як **пошкоджену**. + +Клієнт повинен підписати транзакцію лише за допомогою `account`, зазначеного у +запиті, і зробити це лише у випадку, якщо очікується підпис для цього `account`. + +Якщо очікується будь-який підпис, окрім підпису для `account` у запиті, клієнт +повинен відхилити транзакцію як **шкідливу**. + +### Помилки дій + +API для дій повинні повертати помилки у форматі `ActionError`, щоб надати +корисні повідомлення про помилки для користувачів. Залежно від контексту, ця +помилка може бути фатальною або нефатальною. + +```ts filename="ActionError" +export interface ActionError { + /** simple error message to be displayed to the user */ + message: string; +} +``` + +Коли API для дій відповідає HTTP-кодом помилки (тобто 4xx і 5xx), тіло відповіді +має бути JSON-навантаженням, яке відповідає формату `ActionError`. Помилка +вважається фатальною, і повідомлення, яке міститься в ній, має бути представлене +користувачеві. + +Для відповідей API, які підтримують необов'язковий атрибут `error` (наприклад, +[`ActionGetResponse`](#get-response)), помилка вважається нефатальною, і +повідомлення, яке міститься в ній, також має бути представлене користувачеві. + +## Зчеплення дій + +Дії Solana можуть бути "зчеплені" разом у послідовну серію. Після підтвердження +транзакції дії у блокчейні можна отримати наступну дію та представити її +користувачеві. + +Зчеплення дій дозволяє розробникам створювати більш складний і динамічний досвід +у рамках blinks, включаючи: + +- надання декількох транзакцій (і в майбутньому повідомлень для підпису) + користувачу; +- налаштування метаданих дії залежно від адреси гаманця користувача; +- оновлення метаданих blink після успішної транзакції; +- отримання API-зворотного виклику з підписом транзакції для додаткової + перевірки та логіки на сервері API для дій; +- налаштовані повідомлення про успіх, шляхом оновлення відображуваних метаданих + (наприклад, нове зображення або опис). + +Для зчеплення кількох дій разом, у будь-якому `ActionPostResponse` включіть +`links.next` одного з наступних типів: + +- `PostNextActionLink` — Посилання POST-запиту з URL зворотного виклику того + самого походження для отримання `signature` і `account` користувача у тілі. + Цей URL зворотного виклику повинен відповідати `NextAction`. +- `InlineNextActionLink` — Вбудовані метадані для наступної дії, які мають бути + представлені користувачеві негайно після підтвердження транзакції. Ніякий + зворотний виклик не буде виконано. + +```ts +export type NextActionLink = PostNextActionLink | InlineNextActionLink; + +/** @see {NextActionPostRequest} */ +export interface PostNextActionLink { + /** Indicates the type of the link. */ + type: "post"; + /** Relative or same origin URL to which the POST request should be made. */ + href: string; +} + +/** + * Represents an inline next action embedded within the current context. + */ +export interface InlineNextActionLink { + /** Indicates the type of the link. */ + type: "inline"; + /** The next action to be performed */ + action: NextAction; +} +``` + +### NextAction + +Після того як транзакція, включена в `ActionPostResponse`, підписана +користувачем і підтверджена у блокчейні, blink-клієнт повинен або: + +- виконати запит зворотного виклику, щоб отримати і відобразити `NextAction`, + або +- якщо `NextAction` вже надана через `links.next`, blink-клієнт повинен оновити + відображувані метадані і не робити запит зворотного виклику. + +Якщо URL зворотного виклику не має того ж походження, що і початковий +POST-запит, запит зворотного виклику не повинен виконуватися. Blink-клієнти +повинні відобразити помилку, що повідомляє користувача. + +```ts filename="NextAction" +/** The next action to be performed */ +export type NextAction = Action<"action"> | CompletedAction; + +/** The completed action, used to declare the "completed" state within action chaining. */ +export type CompletedAction = Omit, "links">; +``` + +### Відповідно до `type`, наступна дія повинна бути представлена користувачеві через blink-клієнти одним із наступних способів: + +- `action` - (за замовчуванням) Стандартна дія, яка дозволяє користувачеві + переглядати включені метадані Action, взаємодіяти з наданими `LinkedActions` і + продовжувати виконувати будь-які наступні дії в ланцюжку. + +- `completed` - Завершальний стан ланцюжка дій, який може оновлювати інтерфейс + blink із включеними метаданими Action, але не дозволяє користувачеві + виконувати подальші дії. + +Якщо `links.next` не надано, blink-клієнти повинні припустити, що поточна дія є +фінальною у ланцюжку, і представити свій інтерфейс "завершеної" дії після +підтвердження транзакції. + +## actions.json + +Файл [`actions.json`](#actionsjson) використовується для того, щоб додаток міг +інструктувати клієнтів про те, які URL-адреси вебсайту підтримують Solana +Actions, і надавати мапінг, який може бути використаний для виконання +[GET запитів](#get-request) до серверу API дій. + + + +Відповідь файлу `actions.json` також повинна повертати дійсні заголовки +Cross-Origin для запитів `GET` і `OPTIONS`, зокрема заголовок +`Access-Control-Allow-Origin` із значенням `*`. + +Детальніше див. у розділі [OPTIONS response](#options-response) вище. + + + +Файл `actions.json` повинен бути збережений і загальнодоступний у кореневій +директорії домену. + +Наприклад, якщо ваш вебдодаток розгорнуто на `my-site.com`, тоді файл +`actions.json` має бути доступний за адресою `https://my-site.com/actions.json`. +Цей файл також має бути доступний через будь-який браузер за допомогою заголовка +`Access-Control-Allow-Origin` із значенням `*`. + +### Правила + +Поле `rules` дозволяє додатку мапувати набір відносних маршрутів вебсайту на +інші шляхи. + +**Тип:** `Array` з `ActionRuleObject`. + +```ts filename="ActionRuleObject" +interface ActionRuleObject { + /** relative (preferred) or absolute path to perform the rule mapping from */ + pathPattern: string; + /** relative (preferred) or absolute path that supports Action requests */ + apiPath: string; +} +``` + +- [`pathPattern`](#rules-pathpattern) - Шаблон, який відповідає кожному вхідному + шляху. + +- [`apiPath`](#rules-apipath) - Місце призначення, визначене як абсолютний шлях + або зовнішній URL. + +#### Правила - pathPattern + +Шаблон, який відповідає кожному вхідному шляху. Це може бути абсолютний або +відносний шлях, який підтримує наступні формати: + +- **Точне співпадіння**: Відповідає точному URL-шляху. + + - Приклад: `/exact-path` + - Приклад: `https://website.com/exact-path` + +- **Співпадіння з використанням шаблону**: Використовує символи підстановки для + відповідності будь-якій послідовності символів у шляху URL. Це може + відповідати одному (за допомогою `*`) або кільком сегментам (за допомогою + `**`). (Див. [Path Matching](#rules-path-matching) нижче). + + - Приклад: `/trade/*` відповідатиме `/trade/123` і `/trade/abc`, захоплюючи + лише перший сегмент після `/trade/`. + - Приклад: `/category/*/item/**` відповідатиме `/category/123/item/456` і + `/category/abc/item/def`. + - Приклад: `/api/actions/trade/*/confirm` відповідатиме + `/api/actions/trade/123/confirm`. + +#### Правила - apiPath + +Шлях призначення для запиту дії. Він може бути визначений як абсолютний шлях або +зовнішній URL. + +- Приклад: `/api/exact-path` +- Приклад: `https://api.example.com/v1/donate/*` +- Приклад: `/api/category/*/item/*` +- Приклад: `/api/swap/**` + +#### Правила - Query Parameters + +Параметри запиту з оригінального URL завжди зберігаються та додаються до +мапованого URL. + +#### Правила - Path Matching + +Наступна таблиця описує синтаксис для шаблонів відповідності шляхів: + +| Оператор | Відповідає | +| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `*` | Один сегмент шляху, що не включає оточуючі символи розділювача шляху `/`. | +| `**` | Відповідає нулю або більшій кількості символів, включаючи будь-які символи розділювача шляху `/` між декількома сегментами шляху. Якщо включені інші оператори, оператор `**` повинен бути останнім. | +| `?` | Непідтримуваний шаблон. | + +### Приклади Правил + +Наступний приклад демонструє правило точного співпадіння для мапування запитів +до `/buy` з кореня вашого сайту на точний шлях `/api/buy`, відносно кореня +вашого сайту: + +```json filename="actions.json" +{ + "rules": [ + { + "pathPattern": "/buy", + "apiPath": "/api/buy" + } + ] +} +``` + +Наступний приклад використовує шаблонне співставлення шляху для відображення +запитів до будь-якого шляху (за винятком підкаталогів) під `/actions/` від +кореня вашого сайту до відповідного шляху під `/api/actions/`, відносно кореня +вашого сайту: + +```json filename="actions.json" +{ + "rules": [ + { + "pathPattern": "/actions/*", + "apiPath": "/api/actions/*" + } + ] +} +``` + +Наступний приклад використовує зіставлення шляхів із використанням символів +підстановки для перенаправлення запитів до будь-якого шляху (за винятком +підкаталогів) під `/donate/` у кореневій директорії вашого сайту до відповідного +абсолютного шляху `https://api.dialect.com/api/v1/donate/` на зовнішньому сайті: + +```json filename="actions.json" +{ + "rules": [ + { + "pathPattern": "/donate/*", + "apiPath": "https://api.dialect.com/api/v1/donate/*" + } + ] +} +``` + +Наступний приклад використовує зіставлення шляхів із використанням символів +підстановки для ідемпотентного правила, щоб перенаправляти запити до будь-якого +шляху (включаючи підкаталоги) під `/api/actions/` у кореневій директорії вашого +сайту до самого себе: + +> Ідемпотентні правила дозволяють клієнтам blink легше визначати, чи підтримує +> даний шлях запити API дій, без необхідності: +> +> - додавання префіксу `solana-action:` URI, +> - виконання додаткового тестування відповіді, +> - або будь-яких інших спеціальних перевірок. + +```json filename="actions.json" +{ + "rules": [ + { + "pathPattern": "/api/actions/**", + "apiPath": "/api/actions/**" + } + ] +} +``` + +## Ідентифікація Дії (Action Identity) + +Кінцеві точки дій (Action endpoints) можуть включати _Ідентифікацію Дії_ у +транзакціях, які повертаються у [POST-відповіді](#post-response) для підпису +користувачем. Це дозволяє індексаторам та аналітичним платформам легко та +достовірно приписувати активність у блокчейні конкретному провайдеру дій (тобто +сервісу). + +[Ідентифікація Дії](#action-identity) — це пара ключів (keypair), яка +використовується для підпису спеціально форматованого повідомлення, що +включається до транзакції за допомогою інструкції Memo. Це _Повідомлення +Ідентифікатора_ (_Identifier Message_) може бути достовірно приписане до +конкретної Ідентифікації Дії, а отже, до конкретного провайдера дій. + +Пара ключів не вимагається для підписання самої транзакції. Це дозволяє гаманцям +та додаткам покращити доставку транзакції, якщо у транзакції, поверненій +користувачу, немає інших підписів (див. +[POST-відповідь транзакції](#post-response-transaction)). + +Якщо сценарій використання провайдера дій вимагає, щоб їх бекенд-сервіси +попередньо підписували транзакцію перед тим, як це зробить користувач, вони +мають використовувати цю пару ключів як Ідентифікацію Дії. Це дозволить зменшити +кількість облікових записів у транзакції, скоротивши її загальний розмір на 32 +байти. + +### Повідомлення Ідентифікатора Дії (Action Identifier Message) + +Повідомлення Ідентифікатора Дії — це UTF-8 рядок, розділений двокрапками, який +включається до транзакції за допомогою однієї +[інструкції SPL Memo](https://spl.solana.com/memo). + +```shell +protocol:identity:reference:signature +``` + +- `protocol` - Значення протоколу, який використовується (встановлено як + `solana-action` відповідно до [URL-схеми](#url-scheme) вище). +- `identity` - Значення має бути публічним ключем у форматі base58, який + відповідає парі ключів Ідентифікації Дії. +- `reference` - Значення має бути масивом байтів довжиною 32 у форматі base58. + Це можуть бути як публічні ключі, так і інші дані, які можуть або не можуть + відповідати обліковим записам у Solana. +- `signature` - Підпис у форматі base58, створений парою ключів Ідентифікації + Дії, що підписує лише значення `reference`. + +Значення `reference` має використовуватися тільки один раз і в одній транзакції. +Для приписування транзакцій провайдеру дій, лише перше використання значення +`reference` вважається дійсним. + +Транзакції можуть містити кілька інструкцій Memo. Під час виконання +[`getSignaturesForAddress`](https://solana.com/docs/rpc/http/getsignaturesforaddress) +поле `memo` у результатах повертає повідомлення кожної інструкції Memo як єдиний +рядок, розділений крапкою з комою. + +Жодні інші дані не повинні включатися до інструкції Memo Повідомлення +Ідентифікатора. + +Облікові записи `identity` та `reference` повинні бути включені як доступні +тільки для читання, але без можливості підпису +([ключі](https://solana-labs.github.io/solana-web3.js/v1.x/classes/TransactionInstruction.html#keys)) +у транзакції в інструкції, яка не є Інструкцією Memo Повідомлення +Ідентифікатора. + +Інструкція Memo Повідомлення Ідентифікатора не повинна містити жодних облікових +записів. Якщо облікові записи надаються, програма Memo вимагає, щоб ці облікові +записи були дійсними підписувачами. Це обмежує гнучкість і може погіршити досвід +користувача, тому це вважається антипатерном і має бути уникнуто. + +### Перевірка Ідентифікації Дії (Action Identity Verification) + +Будь-яка транзакція, що включає обліковий запис `identity`, може бути достовірно +пов'язана з провайдером дій за допомогою багатоступінчастого процесу: + +1. Отримайте всі транзакції для заданого `identity`. +2. Розберіть і перевірте рядок memo кожної транзакції, переконавшись, що підпис + `signature` дійсний для збереженого значення `reference`. +3. Перевірте, чи є ця транзакція першим випадком використання `reference` у + блокчейні: + - Якщо ця транзакція є першим випадком, вона вважається підтвердженою і може + бути достовірно приписана провайдеру дій. + - Якщо ця транзакція НЕ є першим випадком, вона вважається недійсною і, + відповідно, не може бути приписана провайдеру дій. + +Оскільки валідатори Solana індексують транзакції за обліковими записами, метод +RPC +[`getSignaturesForAddress`](https://solana.com/docs/rpc/http/getsignaturesforaddress) +може бути використаний для визначення всіх транзакцій, що включають обліковий +запис `identity`. + +Відповідь цього методу RPC включає всі дані Memo у полі `memo`. Якщо в +транзакції було використано кілька інструкцій Memo, кожне повідомлення Memo буде +включено в це поле `memo` і має бути відповідним чином розібране перевіряючою +стороною для отримання _Повідомлення Ідентифікації_. + +Ці транзакції спочатку мають вважатися **НЕПЕРЕВІРЕНИМИ**. Це пов'язано з тим, +що `identity` не вимагається для підписання транзакції, що дозволяє будь-якій +транзакції включати цей обліковий запис як не-підписувач. Це потенційно може +штучно збільшити статистику приписування та використання. + +Повідомлення Ідентифікації має бути перевірене для забезпечення того, що +`signature` було створено `identity`, підписуючи `reference`. Якщо ця перевірка +підпису не вдається, транзакція вважається недійсною. + +Якщо перевірка підпису успішна, перевіряюча сторона має забезпечити, що ця +транзакція є першим випадком використання `reference`. Якщо це не так, +транзакція вважається недійсною. diff --git a/docs/locales/uk/advanced/confirmation.md b/docs/locales/uk/advanced/confirmation.md new file mode 100644 index 000000000..08621dfb1 --- /dev/null +++ b/docs/locales/uk/advanced/confirmation.md @@ -0,0 +1,394 @@ +--- +sidebarSortOrder: 1 +sidebarLabel: "Підтвердження та закінчення строку дії" +title: "Підтвердження транзакції та закінчення строку дії" +seoTitle: "Підтвердження транзакції та закінчення строку дії" +description: + "Дізнайтеся, як працює підтвердження транзакцій у Solana і коли транзакція + завершує дію (включаючи перевірку останніх blockhash)." +altRoutes: + - /docs/uk/advanced + - /docs/uk/core/transactions/confirmation +--- + +Проблеми, пов'язані з +[підтвердженням транзакції](/docs/uk/terminology.md#transaction-confirmations), +є поширеними серед нових розробників під час створення застосунків. Ця стаття +має на меті підвищити загальне розуміння механізму підтвердження, який +використовується в блокчейні Solana, включаючи деякі рекомендовані найкращі +практики. + +## Короткий вступ до транзакцій + +Перед тим як розглянути, як працює підтвердження та закінчення строку дії +транзакцій у Solana, давайте коротко розглянемо кілька основ: + +- що таке транзакція, +- життєвий цикл транзакції, +- що таке blockhash, +- і коротке ознайомлення з Proof of History (PoH) і тим, як це стосується + blockhash. + +### Що таке транзакція? + +Транзакції складаються з двох компонентів: +[повідомлення](/docs/uk/terminology.md#message) і +[списку підписів](/docs/uk/terminology.md#signature). Повідомлення транзакції +містить основну інформацію та складається з чотирьох компонентів: + +- **заголовок** з метаданими про транзакцію, +- **список інструкцій** для виконання, +- **список акаунтів**, які потрібно завантажити, +- та **“недавній blockhash”**. + +У цій статті ми зосередимося на +[недавньому blockhash](/docs/uk/terminology.md#blockhash), оскільки він відіграє +важливу роль у підтвердженні транзакції. + +### Життєвий цикл транзакції + +Нижче наведено основні етапи життєвого циклу транзакції. У цій статті +розглядаються всі етапи, крім 1 і 4. + +1. Створення заголовка та списку інструкцій разом із переліком акаунтів, які + потрібно прочитати або записати. +2. Отримання недавнього blockhash та його використання для підготовки + повідомлення транзакції. +3. Симуляція транзакції, щоб переконатися, що вона поводиться очікувано. +4. Запит користувача на підписання підготовленого повідомлення транзакції за + допомогою його приватного ключа. +5. Відправка транзакції до RPC-вузла, який намагається передати її поточному + виробнику блоків. +6. Очікування, що виробник блоку перевірить і додасть транзакцію до свого блоку. +7. Підтвердження того, що транзакція або була включена в блок, або закінчився її + термін дії. + +### Що таке Blockhash? + +[“Blockhash”](/docs/uk/terminology.md#blockhash) означає останній Proof of +History (PoH) хеш для [“слота”](/docs/uk/terminology.md#slot) (опис нижче). +Оскільки Solana використовує PoH як довірений годинник, недавній blockhash +транзакції можна розглядати як **мітку часу**. + +### Коротке нагадування про Proof of History + +Механізм Proof of History у Solana використовує довгий ланцюг рекурсивних хешів +SHA-256 для створення довіреного годинника. Назва “історія” походить від того, +що виробники блоків додають хеш ідентифікаторів транзакцій у потік, щоб +зафіксувати, які транзакції були оброблені в їхньому блоці. + +[Обчислення PoH-хешу](https://github.com/anza-xyz/agave/blob/aa0922d6845e119ba466f88497e8209d1c82febc/entry/src/poh.rs#L79): +`next_hash = hash(prev_hash, hash(transaction_ids))`. + +PoH може використовуватися як довірений годинник, оскільки кожен хеш має бути +створений послідовно. Кожен згенерований блок містить blockhash і список +контрольних точок хешів, званих “ticks,” які дозволяють валідаторам перевіряти +весь ланцюг хешів паралельно та доводити, що певний час дійсно минув. + +## Закінчення строку дії транзакції + +За замовчуванням усі транзакції Solana закінчують строк дії, якщо їх не включено +в блок протягом певного періоду часу. **Переважна більшість** проблем із +підтвердженням транзакцій пов'язана з тим, як RPC-вузли та валідатори виявляють +і обробляють **прострочені** транзакції. Чітке розуміння механізму закінчення +строку дії транзакції допоможе вам діагностувати більшість проблем із +підтвердженням транзакцій. + +### Як працює закінчення строку дії транзакції? + +Кожна транзакція містить “недавній blockhash,” який використовується як часовий +штамп PoH і закінчується, коли цей blockhash більше не вважається “достатньо +недавнім.” + +Коли кожен блок завершується (тобто досягається максимальна висота тиків, +[визначена](https://github.com/anza-xyz/agave/blob/0588ecc6121ba026c65600d117066dbdfaf63444/runtime/src/bank.rs#L3269-L3271), +до "кордону блоку"), фінальний хеш блоку додається до `BlockhashQueue`, яка +зберігає максимум +[300 найновіших blockhash](https://github.com/anza-xyz/agave/blob/e0b0bcc80380da34bb63364cc393801af1e1057f/sdk/program/src/clock.rs#L123-L126). +Під час обробки транзакцій валідатори Solana перевіряють, чи зберігається +недавній blockhash транзакції серед останніх 151 записаних хешів (так званий +"максимальний вік обробки"). Якщо недавній blockhash транзакції +[старший за цей вік](https://github.com/anza-xyz/agave/blob/cb2fd2b632f16a43eff0c27af7458e4e97512e31/runtime/src/bank.rs#L3570-L3571), +транзакція не обробляється. + +> Завдяки поточному +> [максимальному віку обробки, що становить 150](https://github.com/anza-xyz/agave/blob/cb2fd2b632f16a43eff0c27af7458e4e97512e31/sdk/program/src/clock.rs#L129-L131) +> і тому, що "вік" blockhash у черзі є +> [нульовим індексом](https://github.com/anza-xyz/agave/blob/992a398fe8ea29ec4f04d081ceef7664960206f4/accounts-db/src/blockhash_queue.rs#L248-L274), +> фактично є 151 blockhash, які вважаються "достатньо недавніми" і дійсними для +> обробки. + +Оскільки [слоти](/docs/uk/terminology.md#slot) (тобто періоди часу, протягом +яких валідатор може створити блок) налаштовані на тривалість близько +[400 мс](https://github.com/anza-xyz/agave/blob/cb2fd2b632f16a43eff0c27af7458e4e97512e31/sdk/program/src/clock.rs#L107-L109), +але можуть коливатися між 400 мс і 600 мс, певний blockhash можна +використовувати в транзакціях приблизно протягом 60–90 секунд, перш ніж він +вважатиметься простроченим у середовищі виконання. + +### Приклад закінчення строку дії транзакції + +Розгляньмо швидкий приклад: + +1. Валідатор активно створює новий блок для поточного слота. +2. Валідатор отримує транзакцію від користувача з недавнім blockhash `abcd...`. +3. Валідатор перевіряє цей blockhash `abcd...` у списку недавніх blockhash у + `BlockhashQueue` і виявляє, що він був створений 151 блок тому. +4. Оскільки йому рівно 151 блок, транзакція ще не прострочена та може бути + оброблена. +5. Але зачекайте: перед обробкою транзакції валідатор завершує створення + наступного блоку та додає його до `BlockhashQueue`. Потім валідатор починає + створювати блок для наступного слота (валідатори можуть створювати блоки + протягом 4 послідовних слотів). +6. Валідатор перевіряє ту ж транзакцію ще раз і виявляє, що їй тепер 152 блоки. + Вона відхиляється, оскільки занадто стара. :( + +## Чому транзакції закінчують строк дії? + +Це робиться для того, щоб валідатори могли уникнути повторної обробки тієї ж +транзакції. + +Наївний підхід для запобігання повторній обробці полягав би в перевірці кожної +нової транзакції з усією історією транзакцій блокчейна. Але завдяки тому, що +транзакції закінчують строк дії за короткий період часу, валідаторам потрібно +перевіряти лише відносно невеликий набір **недавніх** транзакцій. + +### Other blockchains + +Solana's approach to prevent double processing is quite different from other +blockchains. For example, Ethereum tracks a counter (nonce) for each transaction +sender and will only process transactions that use the next valid nonce. + +Ethereum's approach is simple for validators to implement, but it can be +problematic for users. Many people have encountered situations when their +Ethereum transactions got stuck in a _pending_ state for a long time and all the +later transactions, which used higher nonce values, were blocked from +processing. + +### Інші блокчейни + +Підхід Solana до запобігання повторній обробці транзакцій значно відрізняється +від інших блокчейнів. Наприклад, Ethereum використовує лічильник (nonce) для +кожного відправника транзакцій і обробляє лише транзакції, які використовують +наступний дійсний nonce. + +Підхід Ethereum є простим для реалізації валідаторами, але може викликати +проблеми для користувачів. Багато хто стикався із ситуаціями, коли їхні +транзакції Ethereum залишалися в стані **очікування** протягом тривалого часу, а +всі подальші транзакції з більшими значеннями nonce блокувалися. + +### Переваги на Solana + +Solana має кілька переваг у цьому підході: + +1. Один платник комісії може надсилати кілька транзакцій одночасно, які можуть + оброблятися в будь-якому порядку. Це може статися, якщо ви використовуєте + кілька додатків одночасно. +2. Якщо транзакція не була додана до блоку та закінчила строк дії, користувачі + можуть спробувати знову, знаючи, що їхня попередня транзакція **ніколи** не + буде оброблена. + +Відсутність використання лічильників робить досвід роботи з Solana більш +зрозумілим для користувачів, оскільки вони швидше отримують результат — успіх, +невдачу або закінчення строку дії — та уникають тривалого стану очікування. + +### Недоліки на Solana + +Звісно, є й недоліки: + +1. Валідатори повинні активно відстежувати набір усіх оброблених ідентифікаторів + транзакцій, щоб запобігти їх повторній обробці. +2. Якщо час закінчення строку дії надто короткий, користувачі можуть не + встигнути надіслати свої транзакції до того, як вони стануть недійсними. + +Ці недоліки показують компроміс у тому, як налаштовано строк дії транзакцій. +Якщо збільшити час закінчення строку дії, валідаторам доведеться використовувати +більше пам’яті для відстеження транзакцій. Якщо ж скоротити строк дії, +користувачам буде важче встигнути надіслати свої транзакції. + +Наразі кластери Solana вимагають, щоб транзакції використовували blockhash, який +не старший за 151 блок. + +> У цьому [питанні GitHub](https://github.com/solana-labs/solana/issues/23582) +> надані розрахунки, які оцінюють, що валідаторам mainnet-beta потрібно близько +> 150 МБ пам’яті для відстеження транзакцій. У майбутньому це можна +> оптимізувати, не скорочуючи строк дії транзакцій, як зазначено в цьому +> обговоренні. + +## Поради щодо підтвердження транзакцій + +Як зазначалося раніше, blockhash закінчують строк дії через період, який може +тривати всього **одну хвилину**, коли слоти обробляються з цільовим часом 400 +мс. + +Одна хвилина — це не багато, враховуючи, що клієнту потрібно отримати недавній +blockhash, дочекатися підписання транзакції користувачем, а потім сподіватися, +що надіслана транзакція досягне лідера, який погодиться її обробити. Розглянемо +кілька порад, які допоможуть уникнути невдач підтвердження через закінчення +строку дії транзакцій. + +### Отримуйте blockhash із відповідним рівнем підтвердження + +З огляду на короткий період закінчення строку дії, клієнти та додатки повинні +допомагати користувачам створювати транзакції з blockhash, який є максимально +недавнім. + +Коли ви отримуєте blockhash, рекомендованим RPC API є +[`getLatestBlockhash`](/docs/uk/rpc/http/getLatestBlockhash.mdx). За +замовчуванням цей API використовує рівень підтвердження `finalized`, щоб +повернути blockhash останнього фіналізованого блоку. Проте ви можете змінити цю +поведінку, встановивши параметр `commitment` на інший рівень підтвердження. + +**Рекомендація** + +Рівень підтвердження `confirmed` майже завжди слід використовувати для запитів +RPC, оскільки він зазвичай лише на кілька слотів відстає від рівня `processed` і +має дуже низьку ймовірність належати до відхиленого +[форку](https://docs.anza.xyz/consensus/fork-generation). + +Але ви також можете розглянути інші варіанти: + +- Вибір `processed` дозволяє отримати найбільш недавній blockhash порівняно з + іншими рівнями підтвердження, що дає більше часу на підготовку і обробку + транзакції. Однак через поширеність форків у блокчейні Solana близько 5% + блоків не потрапляють у фіналізований кластер, що створює ризик того, що ваша + транзакція використовує blockhash, що належить до відкинутого форку. + Транзакції з такими blockhash ніколи не будуть вважатися недавніми у + фіналізованому блокчейні. +- Використання + [рівня підтвердження за замовчуванням](/docs/uk/rpc#default-commitment) + `finalized` виключає ризик того, що вибраний blockhash належатиме до + відкинутого форку. Однак це має компроміс: зазвичай є щонайменше 32 слоти + різниці між найбільш недавнім підтвердженим блоком і найбільш недавнім + фіналізованим блоком. Це значно зменшує строк дії ваших транзакцій приблизно + на 13 секунд, що може бути ще більш суттєвим за нестабільних умов кластеру. + +### Використовуйте відповідний рівень підтвердження для preflight + +Якщо ваша транзакція використовує blockhash, отриманий з одного RPC-вузла, але +надсилається або симулюється на іншому, можуть виникнути проблеми через затримку +одного з вузлів. + +Коли RPC-вузли отримують запит `sendTransaction`, вони намагаються визначити +строк дії транзакції, використовуючи найбільш недавній фіналізований блок або +блок, вибраний параметром `preflightCommitment`. **Дуже поширена проблема** +виникає, якщо blockhash транзакції створений після блоку, який використовується +для обчислення строку дії. У такому випадку RPC-вузол лише один раз пересилає +транзакцію, а потім **видаляє** її. + +Аналогічно, при отриманні запиту `simulateTransaction` RPC-вузли симулюють +транзакцію, використовуючи найбільш недавній фіналізований блок або блок, +вибраний параметром `preflightCommitment`. Якщо вибраний блок для симуляції +старіший за blockhash транзакції, симуляція завершиться помилкою “blockhash not +found”. + +**Рекомендація** + +Навіть якщо ви використовуєте `skipPreflight`, **завжди** встановлюйте параметр +`preflightCommitment` на той самий рівень підтвердження, який використовувався +для отримання blockhash транзакції, як для запитів `sendTransaction`, так і +`simulateTransaction`. + +### Уникайте відставання RPC-вузлів під час надсилання транзакцій + +Якщо ваш додаток використовує сервіс пулу RPC або якщо кінцева точка RPC +відрізняється між створенням транзакції та її надсиланням, будьте обережні зі +сценаріями, коли один RPC-вузол відстає від іншого. Наприклад, якщо blockhash +транзакції отримано з одного RPC-вузла, а транзакція надсилається на інший для +обробки або симуляції, другий RPC-вузол може відставати. + +**Рекомендація** + +Для запитів `sendTransaction` клієнти повинні повторно надсилати транзакцію до +RPC-вузла на частих інтервалах, щоб у випадку, якщо RPC-вузол трохи відстає від +кластеру, він врешті-решт виявив транзакцію та її строк дії. + +Для запитів `simulateTransaction` клієнти повинні використовувати параметр +[`replaceRecentBlockhash`](/docs/uk/rpc/http/simulateTransaction.mdx), щоб +інструктувати RPC-вузол замінювати blockhash симульованої транзакції на +blockhash, який завжди буде дійсним для симуляції. + +### Уникайте повторного використання застарілих blockhash + +Навіть якщо ваш додаток отримав дуже недавній blockhash, переконайтеся, що ви не +використовуєте його надто довго. Ідеальний сценарій — отримати свіжий blockhash +безпосередньо перед підписанням транзакції. + +**Рекомендація для додатків** + +Часто запитуйте нові blockhash, щоб забезпечити готовність вашого додатка до +створення транзакції, коли користувач виконує дію. + +**Рекомендація для гаманців** + +Часто запитуйте нові blockhash та оновлюйте blockhash транзакції перед +підписанням, щоб забезпечити її актуальність. + +### Використовуйте надійні RPC-вузли для отримання blockhash + +RPC-вузли можуть відставати від кластеру через навантаження або інші причини, +повертаючи blockhash, який майже вичерпав строк дії. + +**Рекомендація** + +Моніторте стан RPC-вузлів, використовуючи такі методи: + +1. Викликайте API [`getSlot`](/docs/uk/rpc/http/getSlot.mdx) з рівнем + підтвердження `processed` для отримання останнього обробленого слота вузла та + порівняйте його з + [`getMaxShredInsertSlot`](/docs/uk/rpc/http/getMaxShredInsertSlot.mdx), щоб + оцінити відставання вузла. +2. Використовуйте RPC API `getLatestBlockhash` з рівнем підтвердження + `confirmed` на кількох різних RPC-вузлах та обирайте blockhash від вузла, + який повертає найвищий слот для свого + [контекстного слоту](/docs/uk/rpc/index.mdx#rpcresponse-structure). + +### Зачекайте достатньо довго перед закінченням терміну дії + +**Рекомендація** + +При виклику RPC API +[`getLatestBlockhash`](/docs/uk/rpc/http/getLatestBlockhash.mdx) для отримання +останнього blockhash вашої транзакції зверніть увагу на `lastValidBlockHeight` у +відповіді. + +Потім викликайте RPC API +[`getBlockHeight`](/docs/uk/rpc/http/getBlockHeight.mdx) з рівнем підтвердження +`confirmed`, поки він не поверне висоту блоку, більшу за попередньо отриманий +`lastValidBlockHeight`. + +### Розгляньте використання "довготривалих" транзакцій + +Іноді уникнути проблем із закінченням терміну дії транзакції дуже важко +(наприклад, при офлайн-підписанні або нестабільності кластера). Якщо попередні +поради не підходять для вашого випадку використання, ви можете перейти на +використання довготривалих транзакцій (вони вимагають трохи налаштувань). + +Щоб почати використовувати довготривалі транзакції, користувач спочатку повинен +подати транзакцію, яка +[викликає інструкції для створення спеціального "nonce" облікового запису на блокчейні](https://docs.rs/solana-program/latest/solana_program/system_instruction/fn.create_nonce_account.html) +і зберігає в ньому "довготривалий blockhash". У будь-який момент у майбутньому +(доки nonce-аккаунт ще не використаний) користувач може створити довготривалу +транзакцію, дотримуючись двох правил: + +1. Список інструкцій повинен починатися з + [системної інструкції "advance nonce"](https://docs.rs/solana-program/latest/solana_program/system_instruction/fn.advance_nonce_account.html), + яка завантажує їх nonce-аккаунт. +2. Blockhash транзакції повинен дорівнювати довготривалому blockhash, + збереженому nonce-аккаунтом на блокчейні. + +Ось як Solana обробляє ці довготривалі транзакції: + +1. Якщо blockhash транзакції більше не є "недавнім", система перевіряє, чи + починається список інструкцій транзакції з інструкції "advance nonce". +2. Якщо так, система завантажує nonce-аккаунт, вказаний у цій інструкції. +3. Потім перевіряє, чи збережений довготривалий blockhash відповідає blockhash + транзакції. +4. Нарешті, система оновлює blockhash nonce-аккаунту до останнього недавнього + blockhash, щоб гарантувати, що ця ж транзакція не може бути оброблена + повторно. + +Детальніше про роботу цих довготривалих транзакцій ви можете дізнатися з +[оригінальної пропозиції](https://docs.anza.xyz/implemented-proposals/durable-tx-nonces) +та +[ознайомитися з прикладом](/content/guides/advanced/introduction-to-durable-nonces.md) +у документації Solana. diff --git a/docs/locales/uk/advanced/index.md b/docs/locales/uk/advanced/index.md new file mode 100644 index 000000000..d7cb47698 --- /dev/null +++ b/docs/locales/uk/advanced/index.md @@ -0,0 +1,5 @@ +--- +metaOnly: true +title: Додаткові теми +sidebarSortOrder: 3 +--- diff --git a/docs/locales/uk/advanced/lookup-tables.md b/docs/locales/uk/advanced/lookup-tables.md new file mode 100644 index 000000000..3bedf440d --- /dev/null +++ b/docs/locales/uk/advanced/lookup-tables.md @@ -0,0 +1,194 @@ +--- +sidebarSortOrder: 4 +title: Таблиці пошуку адрес +description: + Дізнайтеся, як використовувати таблиці пошуку адрес Solana (ALTs) для + ефективної обробки до 64 адрес у кожній транзакції. Створюйте, розширюйте та + використовуйте таблиці пошуку за допомогою web3.js. +--- + +Таблиці пошуку адрес, зазвичай відомі як "_lookup tables_" або скорочено +"_ALTs_", дозволяють розробникам створювати колекції пов’язаних адрес для +ефективного завантаження більшої кількості адрес в одній транзакції. + +Оскільки кожна транзакція в блокчейні Solana вимагає переліку всіх адрес, з +якими вона взаємодіє, цей перелік фактично обмежується 32 адресами на +транзакцію. Завдяки [Таблицям пошуку адрес](/docs/uk/advanced/lookup-tables.md) +це обмеження можна збільшити до 64 адрес у кожній транзакції. + +## Стиснення адрес на блокчейні + +Після того, як усі необхідні адреси були збережені на блокчейні у Таблиці пошуку +адрес, кожну адресу можна посилатися в транзакції за її 1-байтовим індексом у +таблиці (замість повної 32-байтової адреси). Цей метод пошуку ефективно +"_стискає_" 32-байтову адресу до 1-байтового значення індексу. + +Таке "_стиснення_" дозволяє зберігати до 256 адрес у одній таблиці пошуку для +використання у будь-якій транзакції. + +## Версійні транзакції + +Щоб використовувати Таблицю пошуку адрес у транзакції, розробники повинні +застосовувати транзакції версії v0, які були запроваджені з новим форматом +[Версійних транзакцій](/docs/uk/advanced/versions.md). + +## Як створити таблицю пошуку адрес + +Створення нової таблиці пошуку за допомогою бібліотеки `@solana/web3.js` подібне +до старішого формату `legacy` транзакцій, але має певні відмінності. + +Використовуючи бібліотеку `@solana/web3.js`, ви можете скористатися функцією +[`createLookupTable`](https://solana-labs.github.io/solana-web3.js/v1.x/classes/AddressLookupTableProgram.html#createLookupTable) +для створення інструкції, необхідної для створення нової таблиці пошуку, а також +для визначення її адреси. + +```js +const web3 = require("@solana/web3.js"); + +// connect to a cluster and get the current `slot` +const connection = new web3.Connection(web3.clusterApiUrl("devnet")); +const slot = await connection.getSlot(); + +// Assumption: +// `payer` is a valid `Keypair` with enough SOL to pay for the execution + +const [lookupTableInst, lookupTableAddress] = + web3.AddressLookupTableProgram.createLookupTable({ + authority: payer.publicKey, + payer: payer.publicKey, + recentSlot: slot, + }); + +console.log("lookup table address:", lookupTableAddress.toBase58()); + +// To create the Address Lookup Table onchain: +// send the `lookupTableInst` instruction in a transaction +``` + +> ПРИМІТКА: Таблиці пошуку адрес можуть бути **створені** за допомогою як +> транзакцій `v0`, так і `legacy`. Але виконуюче середовище Solana може +> отримувати та обробляти додаткові адреси в таблиці пошуку лише під час +> використання +> [Версійних транзакцій v0](/docs/uk/advanced/versions.md#current-transaction-versions). + +## Додавання адрес до таблиці пошуку + +Додавання адрес до таблиці пошуку відоме як "_розширення_" ("_extending_"). +Використовуючи бібліотеку `@solana/web3.js`, ви можете створити нову інструкцію +для _розширення_ за допомогою методу +[`extendLookupTable`](https://solana-labs.github.io/solana-web3.js/v1.x/classes/AddressLookupTableProgram.html#extendLookupTable): + +```js +// add addresses to the `lookupTableAddress` table via an `extend` instruction +const extendInstruction = web3.AddressLookupTableProgram.extendLookupTable({ + payer: payer.publicKey, + authority: payer.publicKey, + lookupTable: lookupTableAddress, + addresses: [ + payer.publicKey, + web3.SystemProgram.programId, + // list more `publicKey` addresses here + ], +}); + +// Send this `extendInstruction` in a transaction to the cluster +// to insert the listing of `addresses` into your lookup table with address `lookupTableAddress` +``` + +> ПРИМІТКА: Через ті самі обмеження пам'яті транзакцій `legacy`, будь-яка +> транзакція, яка використовується для _розширення_ таблиці пошуку адрес, також +> обмежена в кількості адрес, які можна додати одночасно. Через це вам потрібно +> буде використовувати кілька транзакцій, щоб _розширити_ будь-яку таблицю +> більшою кількістю адрес (приблизно 20), ніж це дозволяють обмеження пам'яті +> однієї транзакції. + +Після того як ці адреси були вставлені в таблицю та збережені в блокчейні, ви +зможете використовувати таблицю пошуку адрес у майбутніх транзакціях. Це +дозволяє включити до 64 адрес у цих транзакціях. + +## Отримання таблиці пошуку адрес + +Аналогічно запиту іншого облікового запису (або PDA) з кластера, ви можете +отримати повну таблицю пошуку адрес за допомогою методу +[`getAddressLookupTable`](https://solana-labs.github.io/solana-web3.js/v1.x/classes/Connection.html#getAddressLookupTable): + +```js +// define the `PublicKey` of the lookup table to fetch +const lookupTableAddress = new web3.PublicKey(""); + +// get the table from the cluster +const lookupTableAccount = ( + await connection.getAddressLookupTable(lookupTableAddress) +).value; + +// `lookupTableAccount` will now be a `AddressLookupTableAccount` object + +console.log("Table address from cluster:", lookupTableAccount.key.toBase58()); +``` + +Змінна `lookupTableAccount` тепер буде об'єктом типу +`AddressLookupTableAccount`, який можна проаналізувати для читання списку всіх +адрес, збережених у таблиці пошуку в блокчейні: + +```js +// loop through and parse all the addresses stored in the table +for (let i = 0; i < lookupTableAccount.state.addresses.length; i++) { + const address = lookupTableAccount.state.addresses[i]; + console.log(i, address.toBase58()); +} +``` + +## Як використовувати таблицю пошуку адрес у транзакції + +Після того як ви створили таблицю пошуку і зберегли необхідні адреси в блокчейні +(через розширення таблиці пошуку), ви можете створити транзакцію `v0`, щоб +скористатися можливостями пошуку адрес в блокчейні. + +Так само, як і для старих транзакцій `legacy`, ви можете створити всі +[інструкції](/docs/uk/terminology.md#instruction), які ваша транзакція +виконуватиме в блокчейні. Потім ви можете передати масив цих інструкцій у +[Message](/docs/uk/terminology.md#message), що використовується в транзакції +`v0`. + +> **Примітка:** Інструкції, що використовуються в транзакції `v0`, можна +> створювати за допомогою тих самих методів і функцій, які використовувалися +> раніше для створення інструкцій. Немає необхідності змінювати інструкції, +> пов'язані з використанням таблиці пошуку адрес. + +```js +// Assumptions: +// - `arrayOfInstructions` has been created as an `array` of `TransactionInstruction` +// - we are using the `lookupTableAccount` obtained above + +// construct a v0 compatible transaction `Message` +const messageV0 = new web3.TransactionMessage({ + payerKey: payer.publicKey, + recentBlockhash: blockhash, + instructions: arrayOfInstructions, // note this is an array of instructions +}).compileToV0Message([lookupTableAccount]); + +// create a v0 transaction from the v0 message +const transactionV0 = new web3.VersionedTransaction(messageV0); + +// sign the v0 transaction using the file system wallet we created named `payer` +transactionV0.sign([payer]); + +// send and confirm the transaction +// (NOTE: There is NOT an array of Signers here; see the note below...) +const txid = await web3.sendAndConfirmTransaction(connection, transactionV0); + +console.log( + `Transaction: https://explorer.solana.com/tx/${txid}?cluster=devnet`, +); +``` + +> **Примітка:** Під час відправлення `VersionedTransaction` до кластеру, вона +> має бути підписана **ДО** виклику методу `sendAndConfirmTransaction`. Якщо +> передати масив `Signer` (як у транзакціях `legacy`), метод викличе помилку! + +## Додаткові ресурси + +- Ознайомтеся з + [пропозицією](https://docs.anza.xyz/proposals/versioned-transactions) щодо + таблиць пошуку адрес і версійованих транзакцій +- [Приклад програми на Rust, яка використовує таблиці пошуку адрес](https://github.com/TeamRaccoons/address-lookup-table-multi-swap) diff --git a/docs/locales/uk/advanced/retry.md b/docs/locales/uk/advanced/retry.md new file mode 100644 index 000000000..9a5af666f --- /dev/null +++ b/docs/locales/uk/advanced/retry.md @@ -0,0 +1,194 @@ +--- +sidebarSortOrder: 2 +title: Повторна відправка транзакцій +altRoutes: + - /docs/core/transactions/retry +description: + Дізнайтеся, як обробляти втрачені транзакції та впроваджувати користувацьку + логіку повторної відправки у Solana. Цей посібник охоплює повторне передавання + транзакцій, перевірки перед виконанням (preflight) і найкращі практики для + забезпечення надійної обробки транзакцій у блокчейні Solana. +--- + +# Повторна відправка транзакцій + +Іноді здається, що дійсна транзакція може бути втрачена до її включення в блок. +Це зазвичай трапляється під час завантаженості мережі, коли RPC-вузол не може +повторно передати транзакцію до [лідера](/docs/uk/terminology.md#leader). Для +кінцевого користувача це може виглядати так, ніби транзакція повністю зникає. +Хоча RPC-вузли мають універсальний алгоритм повторного передавання, розробники +додатків також можуть створювати власну логіку повторної передачі. + +## Коротко: + +- RPC-вузли намагатимуться повторно передати транзакції за допомогою + універсального алгоритму. +- Розробники додатків можуть впроваджувати власну логіку повторного передавання. +- Розробникам слід використовувати параметр `maxRetries` у методі JSON-RPC + `sendTransaction`. +- Розробникам слід вмикати перевірки перед виконанням (preflight), щоб виявляти + помилки до відправки транзакцій. +- Перед повторним підписанням будь-якої транзакції важливо переконатися, що + термін дії blockhash вихідної транзакції минув. + +## Шлях транзакції + +### Як клієнти відправляють транзакції + +У Solana немає концепції мемпулу. Усі транзакції, незалежно від того, чи +ініційовані вони програмно або користувачем, ефективно маршрутизуються до +лідерів для обробки в блоках. Є два основні способи надсилання транзакцій до +лідерів: + +1. Через RPC-сервер за допомогою методу JSON-RPC + [sendTransaction](/docs/uk/rpc/http/sendTransaction.mdx). +2. Безпосередньо до лідерів через + [TPU Client](https://docs.rs/solana-client/latest/solana_client/tpu_client/index.html). + +Більшість користувачів відправляють транзакції через RPC-сервер. Коли клієнт +надсилає транзакцію, RPC-вузол намагається передати її поточному та наступному +лідерам. Поки транзакція не буде оброблена лідером, вона існує лише у вигляді +запису в клієнта або проміжних RPC-вузлів. У випадку використання TPU клієнтом, +передавання та маршрутизація обробляються програмним забезпеченням клієнта. + +![Огляд шляху транзакції, від клієнта до лідера](/assets/docs/rt-tx-journey.png) + +### Як RPC-вузли передають транзакції + +Після отримання транзакції через `sendTransaction`, RPC-вузол перетворює +транзакцію в [UDP](https://uk.wikipedia.org/wiki/UDP) пакет і передає його +відповідним лідерам. UDP дозволяє вузлам швидко обмінюватися даними, але не +гарантує доставки пакетів. + +Оскільки розклад лідерів Solana відомий заздалегідь для кожного +[епоха](/docs/uk/terminology.md#epoch) (~2 дні), RPC-вузол передає транзакції +безпосередньо до поточного та наступного лідерів. За замовчуванням RPC-вузли +намагаються повторно передавати транзакції кожні дві секунди, доки транзакція не +буде завершена або доки термін дії її blockhash не закінчиться (~1 хвилина 19 +секунд). Якщо черга для повторної передачі перевищує +[10,000 транзакцій](https://github.com/solana-labs/solana/blob/bfbbc53dac93b3a5c6be9b4b65f679fdb13e41d9/send-transaction-service/src/send_transaction_service.rs#L20), +нові транзакції скидаються. + +![Процес обробки транзакцій TPU](/assets/docs/rt-tpu-jito-labs.png) + +## Як транзакції скидаються + +Транзакції можуть бути скинуті через кілька причин, таких як перевантаження +мережі, втрати пакетів UDP або конфлікти через різні статуси вузлів у пулі RPC. + +## Обробка скинутих транзакцій + +Розробники можуть використовувати параметр `maxRetries` методу `sendTransaction` +для створення власної логіки повторного передавання, зокрема перевірки +`lastValidBlockHeight` і опитування стану мережі. + +## Налаштування власної логіки + +Впровадження алгоритмів, таких як +[експоненціальне збільшення інтервалів](https://uk.wikipedia.org/wiki/Експоненційне_зростання), +або постійне повторне передавання, як у +[Mango](https://github.com/blockworks-foundation/mango-ui/blob/b6abfc6c13b71fc17ebbe766f50b8215fa1ec54f/src/utils/send.tsx#L713), +може допомогти впоратися із завантаженістю мережі. + +```ts +import { + Keypair, + Connection, + LAMPORTS_PER_SOL, + SystemProgram, + Transaction, +} from "@solana/web3.js"; +import * as nacl from "tweetnacl"; + +const sleep = async (ms: number) => { + return new Promise(r => setTimeout(r, ms)); +}; + +(async () => { + const payer = Keypair.generate(); + const toAccount = Keypair.generate().publicKey; + + const connection = new Connection("http://127.0.0.1:8899", "confirmed"); + + const airdropSignature = await connection.requestAirdrop( + payer.publicKey, + LAMPORTS_PER_SOL, + ); + + await connection.confirmTransaction({ signature: airdropSignature }); + + const blockhashResponse = await connection.getLatestBlockhash(); + const lastValidBlockHeight = blockhashResponse.lastValidBlockHeight - 150; + + const transaction = new Transaction({ + feePayer: payer.publicKey, + blockhash: blockhashResponse.blockhash, + lastValidBlockHeight: lastValidBlockHeight, + }).add( + SystemProgram.transfer({ + fromPubkey: payer.publicKey, + toPubkey: toAccount, + lamports: 1000000, + }), + ); + const message = transaction.serializeMessage(); + const signature = nacl.sign.detached(message, payer.secretKey); + transaction.addSignature(payer.publicKey, Buffer.from(signature)); + const rawTransaction = transaction.serialize(); + let blockheight = await connection.getBlockHeight(); + + while (blockheight < lastValidBlockHeight) { + connection.sendRawTransaction(rawTransaction, { + skipPreflight: true, + }); + await sleep(500); + blockheight = await connection.getBlockHeight(); + } +})(); +``` + +При опитуванні через `getLatestBlockhash` додатки повинні вказувати бажаний +рівень +[зобов'язань (commitment)](/docs/uk/rpc/index.mdx#configuring-state-commitment). +Встановлюючи зобов'язання на рівень `confirmed` (підтверджений) або `finalized` +(~30 блоків після `confirmed`), додаток може уникнути опитування blockhash із +меншості вузлів. + +Якщо додаток має доступ до RPC-вузлів за балансувальником навантаження, він +також може розподіляти своє навантаження між конкретними вузлами. RPC-вузли, які +обслуговують ресурсоємні запити, такі як +[getProgramAccounts](/content/guides/javascript/get-program-accounts.md), можуть +відставати і бути менш ефективними для пересилання транзакцій. Для додатків, що +обробляють транзакції в реальному часі, може бути розумним використовувати +спеціалізовані вузли, які обслуговують лише `sendTransaction`. + +### Вартість пропуску перевірки перед виконанням + +За замовчуванням `sendTransaction` виконує три перевірки перед відправкою +транзакції. Зокрема, `sendTransaction`: + +- Перевіряє, що всі підписи є дійсними. +- Перевіряє, що вказаний blockhash знаходиться в межах останніх 150 блоків. +- Симулює транзакцію на основі слоту банку, зазначеного у `preflightCommitment`. + +У разі, якщо одна з цих перевірок не пройде, `sendTransaction` видасть помилку +до відправки транзакції. Перевірки перед виконанням можуть стати вирішальним +фактором між втратою транзакції та можливістю клієнта обробити помилку. Щоб +гарантувати врахування цих поширених помилок, рекомендується залишати +`skipPreflight` встановленим у значення `false`. + +### Коли потрібно повторно підписувати транзакції + +Попри всі спроби повторного передавання, іноді клієнт може бути змушений +повторно підписати транзакцію. Перед повторним підписанням будь-якої транзакції +**дуже важливо** переконатися, що термін дії blockhash вихідної транзакції +закінчився. Якщо початковий blockhash все ще дійсний, обидві транзакції можуть +бути прийняті мережею. Для кінцевого користувача це виглядатиме як ненавмисне +повторне відправлення однієї і тієї ж транзакції. + +У Solana втрачену транзакцію можна безпечно відхилити, якщо blockhash, на який +вона посилається, старший за `lastValidBlockHeight`, отриманий із +`getLatestBlockhash`. Розробникам слід відстежувати цей `lastValidBlockHeight`, +опитуючи [`getEpochInfo`](/docs/uk/rpc/http/getEpochInfo.mdx) і порівнюючи з +`blockHeight` у відповіді. Після того, як blockhash стане недійсним, клієнти +можуть повторно підписати транзакцію з новозапитаним blockhash. diff --git a/docs/locales/uk/advanced/state-compression.md b/docs/locales/uk/advanced/state-compression.md new file mode 100644 index 000000000..b2df0fdc9 --- /dev/null +++ b/docs/locales/uk/advanced/state-compression.md @@ -0,0 +1,296 @@ +--- +sidebarSortOrder: 4 +title: Стиснення стану (State Compression) +description: + 'Стиснення стану - це метод дешевого та безпечного збереження "відбитків" + даних поза мережею в реєстрі Solana замість дорогих облікових записів.' +--- + +У Solana [стиснення стану](/docs/uk/advanced/state-compression.md) є методом +створення "відбитку" (або гешу) даних поза мережею та збереження цього відбитку +в мережі для безпечної перевірки. Цей процес використовує безпеку реєстру Solana +для гарантування цілісності даних поза мережею, забезпечуючи їх незмінність. + +Цей метод "стиснення" дозволяє програмам та децентралізованим додаткам (dApps) +використовувати дешевий простір у [реєстрі](/docs/uk/terminology.md#ledger) +блокчейну, замість більш дорогого простору +[облікових записів](/docs/uk/terminology.md#account), для безпечного зберігання +даних. + +Це досягається за допомогою спеціальної структури двійкового дерева, відомого як +[конкурентне мерклеве дерево](#what-is-a-concurrent-merkle-tree), яке створює +геш кожного фрагмента даних (названого `листком`), об'єднує ці геші і зберігає +тільки фінальний геш у мережі. + +## Що таке стиснення стану? + +Простіше кажучи, стиснення стану використовує структури "**_дерев_**" для +криптографічного хешування даних поза мережею детермінованим способом, щоб +обчислити один кінцевий геш, який зберігається у мережі. + +Ці _дерева_ створюються таким "_детермінованим_" процесом: + +- Береться будь-який фрагмент даних. +- Створюється геш цих даних. +- Цей геш зберігається як `листок` на нижньому рівні дерева. +- Кожна пара `листків` об'єднується в геш, створюючи `гілку`. +- Кожна `гілка` також хешується разом. +- Процес повторюється, поки не буде обчислено фінальний `кореневий геш`. + +Цей `кореневий геш` зберігається в мережі як верифіковане **_підтвердження_** +для всіх даних у кожному листку. Це дозволяє криптографічно перевіряти всі дані +поза мережею, використовуючи мінімальну кількість даних у мережі. Таким чином, +значно знижуються витрати на зберігання/перевірку великих обсягів даних завдяки +"стисненню стану". + +## Мерклеві дерева та конкурентні мерклеві дерева + +Стиснення стану у Solana використовує спеціальний тип +[мерклевого дерева](#what-is-a-merkle-tree), який дозволяє виконувати кілька +змін у дереві, зберігаючи його цілісність і валідність. + +Це спеціальне дерево, відоме як +"[конкурентне мерклеве дерево](#what-is-a-concurrent-merkle-tree)", зберігає +"журнал змін" дерева в мережі. Це дозволяє виконувати кілька змін до дерева +(наприклад, у межах одного блоку), не порушуючи підтвердження. + +### Що таке мерклеве дерево? + +[Мерклеве дерево](https://uk.wikipedia.org/wiki/Мерклеве_дерево), або "дерево +гешів", — це двійкова структура, у якій кожен `листок` є криптографічним гешем +даних. Всі вузли, які **не** є листками, називаються `гілками` і є гешами їхніх +дочірніх листків. + +Кожна гілка також хешується разом, поступово піднімаючись вгору, поки не +залишиться один геш. Цей фінальний геш, званий `кореневим гешем`, можна +використовувати разом із "шляхом підтвердження" для перевірки будь-яких даних, +збережених у листковому вузлі. + +### Що таке Конкурентне Мерклеве дерево? + +У високопродуктивних застосунках, таких як +[середовище виконання Solana](/docs/uk/core/fees.md), запити на зміну ончейн +_традиційного мерклевого дерева_ можуть надходити до валідаторів досить швидко +(наприклад, у межах одного слота). У таких випадках кожна зміна даних у листках +повинна виконуватися послідовно. Це призводить до невдачі наступних запитів на +зміну, оскільки кореневий геш і підтвердження стають недійсними після +попередньої зміни в слоті. + +Рішенням цієї проблеми є Конкурентні Мерклеві дерева. + +**Конкурентне Мерклеве дерево** зберігає **захищений журнал змін**, який містить +останні зміни, їх кореневий геш і підтвердження для його обчислення. Цей буфер +змін ("changelog buffer") зберігається ончейн у спеціальному акаунті для кожного +дерева, з обмеженням на максимальну кількість записів у журналі змін +(`maxBufferSize`). + +Коли валідатори отримують кілька запитів на зміну даних у листках у межах одного +слота, ончейн _конкурентне мерклеве дерево_ може використовувати цей буфер змін +як джерело правдивої інформації для більш прийнятних підтверджень. Це дозволяє +виконувати до `maxBufferSize` змін для одного дерева в межах одного слота, що +значно підвищує пропускну здатність. + +## Розмір Конкурентного Мерклевого дерева + +При створенні такого ончейн дерева існує 3 параметри, які визначають розмір +дерева, вартість його створення і кількість одночасних змін: + +1. Максимальна глибина (max depth) +2. Розмір буфера змін (max buffer size) +3. Глибина крони дерева (canopy depth) + +### Максимальна глибина + +"Максимальна глибина" дерева — це **максимальна кількість** переходів від +будь-якого `листка` даних до `кореня` дерева. + +Оскільки мерклеві дерева є двійковими, кожен листок з'єднаний лише з **одним** +іншим листком; вони утворюють `пару листків`. + +Таким чином, `maxDepth` дерева використовується для визначення максимальної +кількості вузлів (тобто елементів даних або `листків`), які можна зберігати у +дереві, за допомогою простої формули: + +```text +nodes_count = 2 ^ maxDepth +``` + +Оскільки глибину дерева потрібно встановити під час його створення, ви повинні +визначити, скільки елементів даних ви хочете зберігати у своєму дереві. Потім, +використовуючи просту формулу вище, ви можете визначити найменше значення +`maxDepth`, яке дозволить зберігати ваші дані. + +#### Приклад 1: Мінтинг 100 NFT + +Якщо ви хочете створити дерево для зберігання 100 стиснутих NFT, вам знадобиться +щонайменше "100 листків" або "100 вузлів". + +```text +// maxDepth=6 -> 64 nodes +2^6 = 64 + +// maxDepth=7 -> 128 nodes +2^7 = 128 +``` + +Ми повинні використовувати значення `maxDepth` рівне `7`, щоб забезпечити +можливість зберігати всі наші дані. + +#### Приклад 2: Мінтинг 15000 NFT + +Якщо ви хочете створити дерево для зберігання 15000 стиснутих NFT, вам +знадобиться щонайменше "15000 листків" або "15000 вузлів". + +```text +// maxDepth=13 -> 8192 nodes +2^13 = 8192 + +// maxDepth=14 -> 16384 nodes +2^14 = 16384 +``` + +Ми повинні використовувати `maxDepth` рівне `14`, щоб забезпечити можливість +зберігати всі наші дані. + +#### Чим більша максимальна глибина, тим вища вартість + +Значення `maxDepth` є одним із основних чинників вартості під час створення +дерева, оскільки ви оплачуєте цю вартість наперед при створенні дерева. Чим +більша глибина дерева, тим більше даних (відбитків або хешів) можна зберігати, +але тим вища вартість. + +--- + +### Максимальний розмір буфера (maxBufferSize) + +"Максимальний розмір буфера" — це максимальна кількість змін, які можуть бути +внесені до дерева, доки кореневий хеш (`root hash`) залишається дійсним. + +Оскільки кореневий хеш є єдиним хешем для всіх даних листків, зміна будь-якого +окремого листка інвалідовує proof, потрібний для всіх наступних спроб змінити +будь-який інший листок у звичайному дереві. + +У випадку [Concurrent Tree](#що-таке-concurrent-merkle-tree), існує журнал змін +для цих proof, який задається під час створення дерева через параметр +`maxBufferSize`. + +--- + +### Глибина козирка (canopyDepth) + +"Глибина козирка" або "розмір козирка" визначає кількість рівнів proof, які +кешуються або зберігаються on-chain для даного proof-шляху. + +Коли виконується дія оновлення для `leaf` (наприклад, передача права власності), +**повний** proof-шлях повинен бути використаний для верифікації початкового +права власності на листок. Це здійснюється шляхом обчислення поточного +`root hash`. + +Для великих дерев потрібно більше proof-вузлів, щоб виконати цю перевірку. +Наприклад, якщо `maxDepth` дорівнює `14`, потрібно `14` proof-вузлів. З +використанням козирка частина цих вузлів зберігається on-chain, зменшуючи +кількість proof-вузлів, які потрібно включити в транзакції. + +Наприклад, дерево з `maxDepth` рівне `14` із козирком розміром `10` +потребуватиме лише `4` proof-вузли на транзакцію. + +![Глибина козирка 1 для Concurrent Merkle Tree з максимальною глибиною 3](/assets/docs/compression/canopy-depth-1.png) + +--- + +#### Чим більша глибина козирка, тим вища вартість + +Значення `canopyDepth` також є одним із основних чинників вартості створення +дерева. Чим більше proof-вузлів зберігається on-chain, тим вища вартість. + +#### Низький козирок обмежує композитність + +Низьке значення `canopyDepth` вимагає більше proof-вузлів у кожній транзакції +оновлення. Це обмежує можливості для інтеграції вашого дерева з іншими +Solana-програмами або dApps. + +Наприклад, дерево, яке використовується для стиснутих NFT з низьким +`canopyDepth`, може дозволяти лише базові дії, як-от передача, але не +підтримувати розширені функції, такі як система ставок. + +--- + +## Вартість створення дерева + +Вартість створення Concurrent Merkle Tree залежить від його параметрів: +`maxDepth`, `maxBufferSize`, і `canopyDepth`. Ці параметри визначають необхідний +простір (у байтах) для дерева. + +Використовуючи метод +[`getMinimumBalanceForRentExemption`](/docs/uk/rpc/http/getminimumbalanceforrentexemption), +можна дізнатися вартість (у лампортах) для виділення цього простору on-chain. + +--- + +### Розрахунок вартості дерева у JavaScript + +У пакеті +[`@solana/spl-account-compression`](https://www.npmjs.com/package/@solana/spl-account-compression) +можна використовувати функцію +[`getConcurrentMerkleTreeAccountSize`](https://solana-labs.github.io/solana-program-library/account-compression/sdk/docs/modules/index.html#getConcurrentMerkleTreeAccountSize) +для розрахунку необхідного простору для дерева з заданими параметрами. + +Далі, за допомогою функції +[`getMinimumBalanceForRentExemption`](https://solana-labs.github.io/solana-web3.js/v1.x/classes/Connection.html#getMinimumBalanceForRentExemption), +можна визначити остаточну вартість (у лампортах) для створення дерева, подібно +до будь-якого іншого акаунта. + +```ts +// calculate the space required for the tree +const requiredSpace = getConcurrentMerkleTreeAccountSize( + maxDepth, + maxBufferSize, + canopyDepth, +); + +// get the cost (in lamports) to store the tree on-chain +const storageCost = + await connection.getMinimumBalanceForRentExemption(requiredSpace); +``` + +### Приклади вартості + +Нижче наведено кілька прикладів вартості для дерев різного розміру, включаючи +кількість можливих листків: + +**Приклад №1: 16,384 вузлів, вартість 0.222 SOL** + +- максимальна глибина: `14`, максимальний розмір буфера: `64` +- максимальна кількість листків: `16,384` +- глибина козирка: `0`, вартість створення приблизно `0.222 SOL` + +**Приклад №2: 16,384 вузлів, вартість 1.134 SOL** + +- максимальна глибина: `14`, максимальний розмір буфера: `64` +- максимальна кількість листків: `16,384` +- глибина козирка: `11`, вартість створення приблизно `1.134 SOL` + +**Приклад №3: 1,048,576 вузлів, вартість 1.673 SOL** + +- максимальна глибина: `20`, максимальний розмір буфера: `256` +- максимальна кількість листків: `1,048,576` +- глибина козирка: `10`, вартість створення приблизно `1.673 SOL` + +**Приклад №4: 1,048,576 вузлів, вартість 15.814 SOL** + +- максимальна глибина: `20`, максимальний розмір буфера: `256` +- максимальна кількість листків: `1,048,576` +- глибина козирка: `15`, вартість створення приблизно `15.814 SOL` + +--- + +## Стиснуті NFT + +Стиснуті NFT є одним із найпопулярніших варіантів використання стиснення стану +на Solana. Завдяки стисненню колекцію з одного мільйона NFT можна створити за +`~50 SOL`, у порівнянні з `~12,000 SOL` для її нестиснутої еквівалентної +колекції. + +Якщо ви зацікавлені в створенні стиснутих NFT, ознайомтеся з нашим посібником +для розробників: +[створення та передача стиснутих NFT](/content/guides/javascript/compressed-nfts.md). diff --git a/docs/locales/uk/advanced/versions.md b/docs/locales/uk/advanced/versions.md new file mode 100644 index 000000000..998915a05 --- /dev/null +++ b/docs/locales/uk/advanced/versions.md @@ -0,0 +1,178 @@ +--- +sidebarSortOrder: 3 +title: "Версійні Транзакції" +description: + "Дослідіть основні концепції Solana: транзакції, версійні транзакції, + розширення функціональності в Solana Runtime, таблиці пошуку адрес та інше." +altRoutes: + - /docs/uk/core/transactions/versions +--- + +Версійні Транзакції - це новий формат транзакцій, який дозволяє додаткову +функціональність у Solana Runtime, включаючи +[Таблиці пошуку адрес](/docs/uk/advanced/lookup-tables.md). + +Хоча зміни в ончейн-програмах **НЕ** потрібні для підтримки нової +функціональності версійних транзакцій (або для зворотної сумісності), розробники +**ПОВИННІ** оновити клієнтський код, щоб уникнути +[помилок через різні версії транзакцій](#max-supported-transaction-version). + +## Поточні версії транзакцій + +Solana Runtime підтримує дві версії транзакцій: + +- `legacy` - старий формат транзакцій без додаткових переваг +- `0` - додає підтримку + [Таблиць пошуку адрес](/docs/uk/advanced/lookup-tables.md) + +## Максимально підтримувана версія транзакцій + +Усі RPC-запити, які повертають транзакцію, **_повинні_** вказувати найвищу +версію транзакцій, яку вони підтримують у своїй програмі, використовуючи +параметр `maxSupportedTransactionVersion`, включаючи +[`getBlock`](/docs/uk/rpc/http/getBlock.mdx) та +[`getTransaction`](/docs/uk/rpc/http/getTransaction.mdx). + +RPC-запит завершиться невдачею, якщо буде повернута версійна транзакція, яка має +версію вище встановленої `maxSupportedTransactionVersion`. (наприклад, якщо +повертається транзакція версії `0`, а встановлено `legacy`) + +> УВАГА: Якщо значення `maxSupportedTransactionVersion` не встановлено, тоді +> лише транзакції `legacy` будуть дозволені у відповіді RPC. Таким чином, ваші +> RPC-запити **ПРИЗВЕДУТЬ ДО ПОМИЛКИ**, якщо буде повернута будь-яка транзакція +> версії `0`. + +## Як встановити максимально підтримувану версію + +Ви можете встановити `maxSupportedTransactionVersion`, використовуючи бібліотеку +[`@solana/web3.js`](https://solana-labs.github.io/solana-web3.js/v1.x/) або +шляхом прямого надсилання JSON-запитів до RPC-ендпоінту. + +### Використання web3.js + +Використовуючи бібліотеку +[`@solana/web3.js`](https://solana-labs.github.io/solana-web3.js/v1.x/), ви +можете отримати останній блок або конкретну транзакцію: + +```js +// підключення до кластера `devnet` та отримання поточного `slot` +const connection = new web3.Connection(web3.clusterApiUrl("devnet")); +const slot = await connection.getSlot(); + +// отримання останнього блоку (дозволяючи транзакції версії v0) +const block = await connection.getBlock(slot, { + maxSupportedTransactionVersion: 0, +}); + +// отримання конкретної транзакції (дозволяючи транзакції версії v0) +const getTx = await connection.getTransaction( + "3jpoANiFeVGisWRY5UP648xRXs3iQasCHABPWRWnoEjeA93nc79WrnGgpgazjq4K9m8g2NJoyKoWBV1Kx5VmtwHQ", + { + maxSupportedTransactionVersion: 0, + }, +); +``` + +### JSON-запити до RPC + +Використовуючи стандартний JSON-запит POST, ви можете встановити +`maxSupportedTransactionVersion` при отриманні конкретного блоку: + +```shell +curl https://api.devnet.solana.com -X POST -H "Content-Type: application/json" -d \ +'{"jsonrpc": "2.0", "id":1, "method": "getBlock", "params": [430, { + "encoding":"json", + "maxSupportedTransactionVersion":0, + "transactionDetails":"full", + "rewards":false +}]}' +``` + +## Як створити версійну транзакцію + +Версійні транзакції можна створити подібно до старого методу створення +транзакцій. Є відмінності у використанні певних бібліотек, які слід враховувати. + +Нижче наведено приклад створення версійної транзакції з використанням бібліотеки +`@solana/web3.js` для передачі SOL між двома рахунками. + +#### Примітки: + +- `payer` - це дійсний гаманець `Keypair`, наповнений SOL +- `toAccount` - дійсний `Keypair` + +Спочатку імпортуйте бібліотеку web3.js та створіть `connection` до бажаного +кластера. + +Далі визначте останній `blockhash` і `minRent`, які будуть потрібні для вашої +транзакції та рахунку: + +```js +const web3 = require("@solana/web3.js"); + +// підключення до кластера та отримання мінімальної орендної плати для статусу rent exempt +const connection = new web3.Connection(web3.clusterApiUrl("devnet")); +let minRent = await connection.getMinimumBalanceForRentExemption(0); +let blockhash = await connection + .getLatestBlockhash() + .then(res => res.blockhash); +``` + +Створіть `array` усіх `instructions`, які ви хочете відправити у вашій +транзакції. У прикладі нижче ми створюємо просту інструкцію передачі SOL: + +```js +// створення масиву з вашими інструкціями +const instructions = [ + web3.SystemProgram.transfer({ + fromPubkey: payer.publicKey, + toPubkey: toAccount.publicKey, + lamports: minRent, + }), +]; +``` + +Далі створіть повідомлення у форматі `MessageV0` для вашої транзакції: + +```js +// створення повідомлення, сумісного з v0 +const messageV0 = new web3.TransactionMessage({ + payerKey: payer.publicKey, + recentBlockhash: blockhash, + instructions, +}).compileToV0Message(); +``` + +Потім створіть нову `VersionedTransaction`, передаючи ваше повідомлення v0: + +```js +const transaction = new web3.VersionedTransaction(messageV0); + +// підпишіть вашу транзакцію потрібними підписами +transaction.sign([payer]); +``` + +Після того, як ваша `VersionedTransaction` підписана всіма необхідними +рахунками, ви можете відправити її до кластера та отримати відповідь: + +```js +// відправка нашої транзакції v0 до кластера +const txId = await connection.sendTransaction(transaction); +console.log(`https://explorer.solana.com/tx/${txId}?cluster=devnet`); +``` + +> УВАГА: На відміну від `legacy` транзакцій, відправка `VersionedTransaction` +> через `sendTransaction` **НЕ** підтримує підпис транзакцій через передачу +> масиву `Signers` як другого параметра. Ви повинні підписати транзакцію перед +> викликом `connection.sendTransaction()`. + +## Додаткові ресурси + +- Використання + [версійних транзакцій для таблиць пошуку адрес](/docs/uk/advanced/lookup-tables.md#how-to-create-an-address-lookup-table) +- Перегляд + [прикладу транзакції v0](https://explorer.solana.com/tx/h9WQsqSUYhFvrbJWKFPaXximJpLf6Z568NW1j6PBn3f7GPzQXe9PYMYbmWSUFHwgnUmycDNbEX9cr6WjUWkUFKx/?cluster=devnet) + на Solana Explorer +- Читання + [ухваленої пропозиції](https://docs.anza.xyz/proposals/versioned-transactions) + для версійних транзакцій та таблиць пошуку адрес diff --git a/docs/locales/uk/clients/index.md b/docs/locales/uk/clients/index.md new file mode 100644 index 000000000..3f0c7aadd --- /dev/null +++ b/docs/locales/uk/clients/index.md @@ -0,0 +1,5 @@ +--- +metaOnly: true +title: Solana клієнти +sidebarSortOrder: 4 +--- diff --git a/docs/locales/uk/clients/javascript-reference.md b/docs/locales/uk/clients/javascript-reference.md new file mode 100644 index 000000000..1ea13ade9 --- /dev/null +++ b/docs/locales/uk/clients/javascript-reference.md @@ -0,0 +1,857 @@ +--- +title: Web3.js API Приклади +description: + Дізнайтеся, як взаємодіяти з блокчейном Solana за допомогою бібліотеки + @solana/web3.js через практичні приклади коду та пояснення. +--- + +## Довідник по Web3 API + +Бібліотека `@solana/web3.js` забезпечує покриття +[Solana JSON RPC API](/docs/uk/rpc). + +Повну документацію до бібліотеки `@solana/web3.js` можна знайти +[тут](https://solana-labs.github.io/solana-web3.js/v1.x/). + +## Загальні + +### Підключення + +[Документація](https://solana-labs.github.io/solana-web3.js/v1.x/classes/Connection.html) + +Об'єкт `Connection` використовується для взаємодії з +[Solana JSON RPC](/docs/uk/rpc). Ви можете використовувати Connection для +підтвердження транзакцій, отримання інформації про облікові записи тощо. + +Створення підключення здійснюється шляхом вказання URL-адреси RPC-кластера та +бажаного рівня зобов'язань. Після цього ви можете використовувати цей об'єкт +підключення для взаємодії з будь-яким із API JSON RPC Solana. + +#### Приклад використання + +```javascript +const web3 = require("@solana/web3.js"); + +let connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed"); + +let slot = await connection.getSlot(); +console.log(slot); +// 93186439 + +let blockTime = await connection.getBlockTime(slot); +console.log(blockTime); +// 1630747045 + +let block = await connection.getBlock(slot); +console.log(block); + +/* +{ + blockHeight: null, + blockTime: 1630747045, + blockhash: 'AsFv1aV5DGip9YJHHqVjrGg6EKk55xuyxn2HeiN9xQyn', + parentSlot: 93186438, + previousBlockhash: '11111111111111111111111111111111', + rewards: [], + transactions: [] +} +*/ + +let slotLeader = await connection.getSlotLeader(); +console.log(slotLeader); +//49AqLYbpJYc2DrzGUAH1fhWJy62yxBxpLEkfJwjKy2jr +``` + +Наведений вище приклад показує лише кілька методів класу Connection. Повний +список можна знайти у +[генерованій документації](https://solana-labs.github.io/solana-web3.js/v1.x/classes/Connection.html). + +### Транзакція + +[Документація](https://solana-labs.github.io/solana-web3.js/v1.x/classes/Transaction.html) + +Транзакція використовується для взаємодії з програмами на блокчейні Solana. Ці +транзакції створюються за допомогою TransactionInstructions, які містять усі +можливі облікові записи для взаємодії, а також необхідні дані або адреси +програм. Кожна TransactionInstruction складається з ключів, даних і programId. +Ви можете виконувати кілька інструкцій в одній транзакції, взаємодіючи з +кількома програмами одночасно. + +#### Приклад використання + +```javascript +const web3 = require("@solana/web3.js"); +const nacl = require("tweetnacl"); + +// Запит airdrop SOL для оплати транзакцій +let payer = web3.Keypair.generate(); +let connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed"); + +let airdropSignature = await connection.requestAirdrop( + payer.publicKey, + web3.LAMPORTS_PER_SOL, +); + +await connection.confirmTransaction({ signature: airdropSignature }); + +let toAccount = web3.Keypair.generate(); + +// Створення простої транзакції +let transaction = new web3.Transaction(); + +// Додати інструкцію для виконання +transaction.add( + web3.SystemProgram.transfer({ + fromPubkey: payer.publicKey, + toPubkey: toAccount.publicKey, + lamports: 1000, + }), +); + +// Відправка та підтвердження транзакції +// За замовчуванням feePayer - це перший підписант +await web3.sendAndConfirmTransaction(connection, transaction, [payer]); + +// Альтернативно, створення транзакції вручну +let recentBlockhash = await connection.getLatestBlockhash(); +let manualTransaction = new web3.Transaction({ + recentBlockhash: recentBlockhash.blockhash, + feePayer: payer.publicKey, +}); +manualTransaction.add( + web3.SystemProgram.transfer({ + fromPubkey: payer.publicKey, + toPubkey: toAccount.publicKey, + lamports: 1000, + }), +); + +let transactionBuffer = manualTransaction.serializeMessage(); +let signature = nacl.sign.detached(transactionBuffer, payer.secretKey); + +manualTransaction.addSignature(payer.publicKey, signature); + +let isVerifiedSignature = manualTransaction.verifySignatures(); +console.log(`The signatures were verified: ${isVerifiedSignature}`); + +// The signatures were verified: true + +let rawTransaction = manualTransaction.serialize(); + +await web3.sendAndConfirmRawTransaction(connection, rawTransaction); +``` + +### Keypair + +[Документація](https://solana-labs.github.io/solana-web3.js/v1.x/classes/Keypair.html) + +Keypair використовується для створення облікового запису з публічним і секретним +ключами в Solana. Ви можете згенерувати Keypair, створити його з seed або +секретного ключа. + +#### Приклад використання + +```javascript +const { Keypair } = require("@solana/web3.js"); + +let account = Keypair.generate(); + +console.log(account.publicKey.toBase58()); +console.log(account.secretKey); + +// 2DVaHtcdTf7cm18Zm9VV8rKK4oSnjmTkKE6MiXe18Qsb +// Uint8Array(64) [...] + +let seed = Uint8Array.from([ + 70, 60, 102, 100, 70, 60, 102, 100, 70, 60, 102, 100, 70, 60, 102, 100, +]); +let accountFromSeed = Keypair.fromSeed(seed); + +console.log(accountFromSeed.publicKey.toBase58()); +console.log(accountFromSeed.secretKey); + +// 3LDverZtSC9Duw2wyGC1C38atMG49toPNW9jtGJiw9Ar +// Uint8Array(64) [...] + +let accountFromSecret = Keypair.fromSecretKey(account.secretKey); + +console.log(accountFromSecret.publicKey.toBase58()); +console.log(accountFromSecret.secretKey); + +// 2DVaHtcdTf7cm18Zm9VV8rKK4oSnjmTkKE6MiXe18Qsb +// Uint8Array(64) [...] +``` + +Використання `generate` генерує випадкову Keypair для облікового запису на +Solana. Використання `fromSeed` дозволяє створити Keypair з детермінованим +конструктором. `fromSecret` створює Keypair із секретного масиву Uint8Array. Ви +можете побачити, що publicKey для Keypair, створеної за допомогою `generate`, і +`fromSecret` однакові, оскільки секретний ключ однаковий. + +### Використання `generate` створює випадкову пару ключів для використання як обліковий запис у Solana. + +Використання `fromSeed` дозволяє створити пару ключів за допомогою +детермінованого конструктора. `fromSecret` створює пару ключів із секретного +масиву Uint8Array. Ви можете побачити, що publicKey для пари ключів `generate` і +`fromSecret` є однаковими, оскільки секрет від пари ключів `generate` +використовується в `fromSecret`. + +**Попередження**: Не використовуйте `fromSeed`, якщо ви не створюєте seed із +високою ентропією. Не розголошуйте ваш seed. Ставтеся до seed так само, як до +приватного ключа. + +### PublicKey + +[Джерело документації](https://solana-labs.github.io/solana-web3.js/v1.x/classes/PublicKey.html) + +`PublicKey` використовується в `@solana/web3.js` для транзакцій, пар ключів і +програм. Вам потрібен publicKey при зазначенні кожного облікового запису в +транзакції, а також як загальний ідентифікатор у Solana. + +`PublicKey` можна створити за допомогою base58-строки, буфера, Uint8Array, числа +або масиву чисел. + +#### Приклад використання + +```javascript +const { Buffer } = require("buffer"); +const web3 = require("@solana/web3.js"); +const crypto = require("crypto"); + +// Створення PublicKey з base58-строки +let base58publicKey = new web3.PublicKey( + "5xot9PVkphiX2adznghwrAuxGs2zeWisNSxMW6hU6Hkj", +); +console.log(base58publicKey.toBase58()); + +// 5xot9PVkphiX2adznghwrAuxGs2zeWisNSxMW6hU6Hkj + +// Створення програмної адреси +let highEntropyBuffer = crypto.randomBytes(31); +let programAddressFromKey = await web3.PublicKey.createProgramAddress( + [highEntropyBuffer.slice(0, 31)], + base58publicKey, +); +console.log( + `Згенерована програмна адреса: ${programAddressFromKey.toBase58()}`, +); + +// Згенерована програмна адреса: 3thxPEEz4EDWHNxo1LpEpsAxZryPAHyvNVXJEJWgBgwJ + +// Знаходження програмної адреси за PublicKey +let validProgramAddress = await web3.PublicKey.findProgramAddress( + [Buffer.from("", "utf8")], + programAddressFromKey, +); +console.log(`Дійсна програмна адреса: ${validProgramAddress}`); + +// Дійсна програмна адреса: C14Gs3oyeXbASzwUpqSymCKpEyccfEuSe8VRar9vJQRE,253 +``` + +### SystemProgram + +[Джерело документації](https://solana-labs.github.io/solana-web3.js/v1.x/classes/SystemProgram.html) + +`SystemProgram` дозволяє створювати облікові записи, виділяти дані облікових +записів, призначати облікові записи програмам, працювати з nonce-обліковими +записами та переводити лампорти. Ви можете використовувати клас +`SystemInstruction` для декодування та читання окремих інструкцій. + +#### Приклад використання + +```javascript +const web3 = require("@solana/web3.js"); + +// Запит SOL для оплати транзакцій +let payer = web3.Keypair.generate(); +let connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed"); + +let airdropSignature = await connection.requestAirdrop( + payer.publicKey, + web3.LAMPORTS_PER_SOL, +); + +await connection.confirmTransaction({ signature: airdropSignature }); + +// Виділення даних облікового запису +let allocatedAccount = web3.Keypair.generate(); +let allocateInstruction = web3.SystemProgram.allocate({ + accountPubkey: allocatedAccount.publicKey, + space: 100, +}); +let transaction = new web3.Transaction().add(allocateInstruction); + +await web3.sendAndConfirmTransaction(connection, transaction, [ + payer, + allocatedAccount, +]); + +// Створення nonce-облікового запису +let nonceAccount = web3.Keypair.generate(); +let minimumAmountForNonceAccount = + await connection.getMinimumBalanceForRentExemption(web3.NONCE_ACCOUNT_LENGTH); +let createNonceAccountTransaction = new web3.Transaction().add( + web3.SystemProgram.createNonceAccount({ + fromPubkey: payer.publicKey, + noncePubkey: nonceAccount.publicKey, + authorizedPubkey: payer.publicKey, + lamports: minimumAmountForNonceAccount, + }), +); + +await web3.sendAndConfirmTransaction( + connection, + createNonceAccountTransaction, + [payer, nonceAccount], +); + +// Переведення nonce - використовується для створення транзакцій як зберігач облікового запису +let advanceNonceTransaction = new web3.Transaction().add( + web3.SystemProgram.nonceAdvance({ + noncePubkey: nonceAccount.publicKey, + authorizedPubkey: payer.publicKey, + }), +); + +await web3.sendAndConfirmTransaction(connection, advanceNonceTransaction, [ + payer, +]); + +// Переведення лампортів між обліковими записами +let toAccount = web3.Keypair.generate(); + +let transferTransaction = new web3.Transaction().add( + web3.SystemProgram.transfer({ + fromPubkey: payer.publicKey, + toPubkey: toAccount.publicKey, + lamports: 1000, + }), +); +await web3.sendAndConfirmTransaction(connection, transferTransaction, [payer]); + +// Призначення нового облікового запису програмі +let programId = web3.Keypair.generate(); +let assignedAccount = web3.Keypair.generate(); + +let assignTransaction = new web3.Transaction().add( + web3.SystemProgram.assign({ + accountPubkey: assignedAccount.publicKey, + programId: programId.publicKey, + }), +); + +await web3.sendAndConfirmTransaction(connection, assignTransaction, [ + payer, + assignedAccount, +]); +``` + +### Secp256k1Program + +[Документація Джерела](https://solana-labs.github.io/solana-web3.js/v1.x/classes/Secp256k1Program.html) + +`Secp256k1Program` використовується для перевірки підписів `Secp256k1`, які +використовуються як у Bitcoin, так і в Ethereum. + +#### Приклад Використання + +```javascript +const { keccak_256 } = require("js-sha3"); +const web3 = require("@solana/web3.js"); +const secp256k1 = require("secp256k1"); + +// Створення Ethereum адреси з secp256k1 +let secp256k1PrivateKey; +do { + secp256k1PrivateKey = web3.Keypair.generate().secretKey.slice(0, 32); +} while (!secp256k1.privateKeyVerify(secp256k1PrivateKey)); + +let secp256k1PublicKey = secp256k1 + .publicKeyCreate(secp256k1PrivateKey, false) + .slice(1); + +let ethAddress = + web3.Secp256k1Program.publicKeyToEthAddress(secp256k1PublicKey); +console.log(`Ethereum Address: 0x${ethAddress.toString("hex")}`); + +// Ethereum Address: 0xadbf43eec40694eacf36e34bb5337fba6a2aa8ee + +// Фінансування облікового запису для створення інструкцій +let fromPublicKey = web3.Keypair.generate(); +let connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed"); + +let airdropSignature = await connection.requestAirdrop( + fromPublicKey.publicKey, + web3.LAMPORTS_PER_SOL, +); + +await connection.confirmTransaction({ signature: airdropSignature }); + +// Підписування повідомлення з ключем Ethereum +let plaintext = Buffer.from("string address"); +let plaintextHash = Buffer.from(keccak_256.update(plaintext).digest()); +let { signature, recid: recoveryId } = secp256k1.ecdsaSign( + plaintextHash, + secp256k1PrivateKey, +); + +// Створення транзакції для перевірки підпису +let transaction = new Transaction().add( + web3.Secp256k1Program.createInstructionWithEthAddress({ + ethAddress: ethAddress.toString("hex"), + plaintext, + signature, + recoveryId, + }), +); + +// Транзакція буде успішною, якщо повідомлення підтверджено, що його підписано цією адресою +await web3.sendAndConfirmTransaction(connection, transaction, [fromPublicKey]); +``` + +### Message + +[Документація Джерела](https://solana-labs.github.io/solana-web3.js/v1.x/classes/Message.html) + +`Message` використовується як альтернативний спосіб створення транзакцій. Ви +можете створити повідомлення за допомогою облікових записів, заголовка, +інструкцій та недавнього блочного хеша, які є частиною транзакції. +[Transaction](/docs/uk/clients/javascript.md#Transaction) є `Message` плюс +список необхідних підписів для виконання транзакції. + +#### Приклад Використання + +```javascript +const { Buffer } = require("buffer"); +const bs58 = require("bs58"); +const web3 = require("@solana/web3.js"); + +let toPublicKey = web3.Keypair.generate().publicKey; +let fromPublicKey = web3.Keypair.generate(); + +let connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed"); + +let airdropSignature = await connection.requestAirdrop( + fromPublicKey.publicKey, + web3.LAMPORTS_PER_SOL, +); + +await connection.confirmTransaction({ signature: airdropSignature }); + +let type = web3.SYSTEM_INSTRUCTION_LAYOUTS.Transfer; +let data = Buffer.alloc(type.layout.span); +let layoutFields = Object.assign({ instruction: type.index }); +type.layout.encode(layoutFields, data); + +let recentBlockhash = await connection.getRecentBlockhash(); + +let messageParams = { + accountKeys: [ + fromPublicKey.publicKey.toString(), + toPublicKey.toString(), + web3.SystemProgram.programId.toString(), + ], + header: { + numReadonlySignedAccounts: 0, + numReadonlyUnsignedAccounts: 1, + numRequiredSignatures: 1, + }, + instructions: [ + { + accounts: [0, 1], + data: bs58.encode(data), + programIdIndex: 2, + }, + ], + recentBlockhash, +}; + +let message = new web3.Message(messageParams); + +let transaction = web3.Transaction.populate(message, [ + fromPublicKey.publicKey.toString(), +]); + +await web3.sendAndConfirmTransaction(connection, transaction, [fromPublicKey]); +``` + +### Struct + +[Документація Джерела](https://solana-labs.github.io/solana-web3.js/v1.x/classes/Struct.html) + +Клас `Struct` використовується для створення структур, сумісних із Rust, у +JavaScript. Цей клас сумісний лише з Rust-структурами, закодованими за допомогою +Borsh. + +#### Приклад Використання + +Структура в Rust: + +```rust +pub struct Fee { + pub denominator: u64, + pub numerator: u64, +} +``` + +Використання з web3: + +```javascript +import BN from "bn.js"; +import { Struct } from "@solana/web3.js"; + +export class Fee extends Struct { + denominator: BN; + numerator: BN; +} +``` + +### Enum + +[Документація Джерела](https://solana-labs.github.io/solana-web3.js/v1.x/classes/Enum.html) + +Клас `Enum` використовується для представлення сумісного з Rust енумератора у +JavaScript. Енумератор буде представлений як строка при логуванні, але може бути +правильно закодований/декодований при використанні разом з +[Struct](/docs/uk/clients/javascript.md#Struct). Цей клас сумісний лише з +Rust-енумераторами, закодованими за допомогою Borsh. + +#### Приклад Використання + +Rust: + +```rust +pub enum AccountType { + Uninitialized, + StakePool, + ValidatorList, +} +``` + +Web3: + +```javascript +import { Enum } from "@solana/web3.js"; + +export class AccountType extends Enum {} +``` + +### NonceAccount + +[Документація Джерела](https://solana-labs.github.io/solana-web3.js/v1.x/classes/NonceAccount.html) + +Зазвичай транзакція відхиляється, якщо поле `recentBlockhash` транзакції є +застарілим. Для забезпечення певних кастодіальних послуг використовуються +облікові записи `NonceAccount`. Транзакції, які використовують +`recentBlockhash`, зафіксовані на блокчейні обліковим записом `NonceAccount`, не +старіють доти, доки цей обліковий запис не буде оновлено. + +Ви можете створити `NonceAccount`, спочатку створивши звичайний обліковий запис, +а потім використовуючи `SystemProgram`, щоб зробити цей обліковий запис +`NonceAccount`. + +#### Приклад Використання + +```javascript +const web3 = require("@solana/web3.js"); + +// Створення з'єднання +let connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed"); + +// Генерація облікових записів +let account = web3.Keypair.generate(); +let nonceAccount = web3.Keypair.generate(); + +// Фінансування облікового запису +let airdropSignature = await connection.requestAirdrop( + account.publicKey, + web3.LAMPORTS_PER_SOL, +); + +await connection.confirmTransaction({ signature: airdropSignature }); + +// Отримання мінімальної суми для звільнення від оренди +let minimumAmount = await connection.getMinimumBalanceForRentExemption( + web3.NONCE_ACCOUNT_LENGTH, +); + +// Формування транзакції CreateNonceAccount +let transaction = new web3.Transaction().add( + web3.SystemProgram.createNonceAccount({ + fromPubkey: account.publicKey, + noncePubkey: nonceAccount.publicKey, + authorizedPubkey: account.publicKey, + lamports: minimumAmount, + }), +); +// Створення Nonce Account +await web3.sendAndConfirmTransaction(connection, transaction, [ + account, + nonceAccount, +]); + +let nonceAccountData = await connection.getNonce( + nonceAccount.publicKey, + "confirmed", +); + +console.log(nonceAccountData); +// NonceAccount { +// authorizedPubkey: PublicKey { +// _bn: +// }, +// nonce: '93zGZbhMmReyz4YHXjt2gHsvu5tjARsyukxD4xnaWaBq', +// feeCalculator: { lamportsPerSignature: 5000 } +// } + +let nonceAccountInfo = await connection.getAccountInfo( + nonceAccount.publicKey, + "confirmed", +); + +let nonceAccountFromInfo = web3.NonceAccount.fromAccountData( + nonceAccountInfo.data, +); + +console.log(nonceAccountFromInfo); +// NonceAccount { +// authorizedPubkey: PublicKey { +// _bn: +// }, +// nonce: '93zGZbhMmReyz4YHXjt2gHsvu5tjARsyukxD4xnaWaBq', +// feeCalculator: { lamportsPerSignature: 5000 } +// } +``` + +Наведений вище приклад показує як створити `NonceAccount` за допомогою +`SystemProgram.createNonceAccount`, а також як отримати `NonceAccount` з +accountInfo. Використовуючи nonce, ви можете створювати транзакції офлайн з +nonce замість `recentBlockhash`. + +### VoteAccount + +[Документація Джерела](https://solana-labs.github.io/solana-web3.js/v1.x/classes/VoteAccount.html) + +`VoteAccount` — це об'єкт, який дозволяє декодувати облікові записи для +голосування з використанням нативної програми голосування в мережі. + +#### Приклад Використання + +```javascript +const web3 = require("@solana/web3.js"); + +let voteAccountInfo = await connection.getProgramAccounts(web3.VOTE_PROGRAM_ID); +let voteAccountFromData = web3.VoteAccount.fromAccountData( + voteAccountInfo[0].account.data, +); +console.log(voteAccountFromData); +/* +VoteAccount { + nodePubkey: PublicKey { + _bn: + }, + authorizedWithdrawer: PublicKey { + _bn: + }, + commission: 10, + rootSlot: 104570885, + votes: [ + { slot: 104570886, confirmationCount: 31 }, + { slot: 104570887, confirmationCount: 30 }, + { slot: 104570888, confirmationCount: 29 }, + { slot: 104570889, confirmationCount: 28 }, + { slot: 104570890, confirmationCount: 27 }, + { slot: 104570891, confirmationCount: 26 }, + { slot: 104570892, confirmationCount: 25 }, + { slot: 104570893, confirmationCount: 24 }, + { slot: 104570894, confirmationCount: 23 }, + ... + ], + authorizedVoters: [ { epoch: 242, authorizedVoter: [PublicKey] } ], + priorVoters: [ + [Object], [Object], [Object], + [Object], [Object], [Object], + [Object], [Object], [Object], + [Object], [Object], [Object], + [Object], [Object], [Object], + [Object], [Object], [Object], + [Object], [Object], [Object], + [Object], [Object], [Object], + [Object], [Object], [Object], + [Object], [Object] + ], + epochCredits: [ + { epoch: 179, credits: 33723163, prevCredits: 33431259 }, + { epoch: 180, credits: 34022643, prevCredits: 33723163 }, + { epoch: 181, credits: 34331103, prevCredits: 34022643 }, + { epoch: 182, credits: 34619348, prevCredits: 34331103 }, + { epoch: 183, credits: 34880375, prevCredits: 34619348 }, + { epoch: 184, credits: 35074055, prevCredits: 34880375 }, + { epoch: 185, credits: 35254965, prevCredits: 35074055 }, + { epoch: 186, credits: 35437863, prevCredits: 35254965 }, + { epoch: 187, credits: 35672671, prevCredits: 35437863 }, + { epoch: 188, credits: 35950286, prevCredits: 35672671 }, + { epoch: 189, credits: 36228439, prevCredits: 35950286 }, + ... + ], + lastTimestamp: { slot: 104570916, timestamp: 1635730116 } +} +*/ +``` + +## Staking + +### StakeProgram + +[Документація Джерела](https://solana-labs.github.io/solana-web3.js/v1.x/classes/StakeProgram.html) + +`StakeProgram` полегшує процес стейкінгу SOL і делегування їх будь-яким +валідаторам у мережі. Ви можете використовувати `StakeProgram`, щоб створити +стейк-обліковий запис, застейкати SOL, авторизувати облікові записи для +виведення стейка, деактивувати стейк і вивести кошти. Клас `StakeInstruction` +використовується для декодування та читання додаткових інструкцій з транзакцій, +що викликають `StakeProgram`. + +#### Приклад Використання + +```javascript +const web3 = require("@solana/web3.js"); + +// Фінансування ключа для створення транзакцій +let fromPublicKey = web3.Keypair.generate(); +let connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed"); + +let airdropSignature = await connection.requestAirdrop( + fromPublicKey.publicKey, + web3.LAMPORTS_PER_SOL, +); +await connection.confirmTransaction({ signature: airdropSignature }); + +// Створення облікового запису +let stakeAccount = web3.Keypair.generate(); +let authorizedAccount = web3.Keypair.generate(); +/* Примітка: Це мінімальна сума для стейк-облікового запису — Додайте додаткові лампорти для стейкінгу + Наприклад, ми додаємо 50 лампорт як частину стейка */ +let lamportsForStakeAccount = + (await connection.getMinimumBalanceForRentExemption( + web3.StakeProgram.space, + )) + 50; + +let createAccountTransaction = web3.StakeProgram.createAccount({ + fromPubkey: fromPublicKey.publicKey, + authorized: new web3.Authorized( + authorizedAccount.publicKey, + authorizedAccount.publicKey, + ), + lamports: lamportsForStakeAccount, + lockup: new web3.Lockup(0, 0, fromPublicKey.publicKey), + stakePubkey: stakeAccount.publicKey, +}); +await web3.sendAndConfirmTransaction(connection, createAccountTransaction, [ + fromPublicKey, + stakeAccount, +]); + +// Перевірка доступності стейка +let stakeBalance = await connection.getBalance(stakeAccount.publicKey); +console.log(`Stake balance: ${stakeBalance}`); +// Stake balance: 2282930 + +// Ми можемо перевірити стан нашого стейка. Це може зайняти деякий час, щоб активуватись +let stakeState = await connection.getStakeActivation(stakeAccount.publicKey); +console.log(`Stake state: ${stakeState.state}`); +// Stake state: inactive + +// Щоб делегувати наш стейк, ми отримуємо поточні облікові записи голосування та вибираємо перший +let voteAccounts = await connection.getVoteAccounts(); +let voteAccount = voteAccounts.current.concat(voteAccounts.delinquent)[0]; +let votePubkey = new web3.PublicKey(voteAccount.votePubkey); + +// Тепер ми можемо делегувати наш стейк до облікового запису голосування +let delegateTransaction = web3.StakeProgram.delegate({ + stakePubkey: stakeAccount.publicKey, + authorizedPubkey: authorizedAccount.publicKey, + votePubkey: votePubkey, +}); +await web3.sendAndConfirmTransaction(connection, delegateTransaction, [ + fromPublicKey, + authorizedAccount, +]); + +// Щоб вивести наші кошти, ми спочатку повинні деактивувати стейк +let deactivateTransaction = web3.StakeProgram.deactivate({ + stakePubkey: stakeAccount.publicKey, + authorizedPubkey: authorizedAccount.publicKey, +}); +await web3.sendAndConfirmTransaction(connection, deactivateTransaction, [ + fromPublicKey, + authorizedAccount, +]); + +// Після деактивації ми можемо вивести наші кошти +let withdrawTransaction = web3.StakeProgram.withdraw({ + stakePubkey: stakeAccount.publicKey, + authorizedPubkey: authorizedAccount.publicKey, + toPubkey: fromPublicKey.publicKey, + lamports: stakeBalance, +}); + +await web3.sendAndConfirmTransaction(connection, withdrawTransaction, [ + fromPublicKey, + authorizedAccount, +]); +``` + +### Authorized + +[Документація Джерела](https://solana-labs.github.io/solana-web3.js/v1.x/classes/Authorized.html) + +`Authorized` — це об'єкт, який використовується під час створення авторизованого +облікового запису для стейкінгу в Solana. Ви можете окремо призначити `staker` і +`withdrawer`, що дозволяє іншому обліковому запису виводити кошти, ніж той, що +виконує стейкінг. + +Більше прикладів використання об'єкта `Authorized` ви можете знайти в розділі +[`StakeProgram`](/docs/uk/clients/javascript.md#StakeProgram). + +### Lockup + +[Документація Джерела](https://solana-labs.github.io/solana-web3.js/v1.x/classes/Lockup.html) + +`Lockup` використовується разом із +[StakeProgram](/docs/uk/clients/javascript.md#StakeProgram) для створення +облікового запису. `Lockup` визначає, як довго стейк буде заблокований або +недоступний для вилучення. Якщо `Lockup` встановлений на 0 як для епохи, так і +для мітки часу Unix, блокування для облікового запису буде відключено. + +#### Приклад Використання + +```javascript +const { + Authorized, + Keypair, + Lockup, + StakeProgram, +} = require("@solana/web3.js"); + +let account = Keypair.generate(); +let stakeAccount = Keypair.generate(); +let authorized = new Authorized(account.publicKey, account.publicKey); +let lockup = new Lockup(0, 0, account.publicKey); + +let createStakeAccountInstruction = StakeProgram.createAccount({ + fromPubkey: account.publicKey, + authorized: authorized, + lamports: 1000, + lockup: lockup, + stakePubkey: stakeAccount.publicKey, +}); +``` + +Наведений вище код створює `createStakeAccountInstruction`, який +використовується для створення облікового запису за допомогою `StakeProgram`. +Блокування встановлено на 0 як для епохи, так і для мітки часу Unix, що +відключає блокування для облікового запису. + +Детальніше див. у розділі +[StakeProgram](/docs/uk/clients/javascript.md#StakeProgram). diff --git a/docs/locales/uk/clients/javascript.md b/docs/locales/uk/clients/javascript.md new file mode 100644 index 000000000..482da4c62 --- /dev/null +++ b/docs/locales/uk/clients/javascript.md @@ -0,0 +1,409 @@ +--- +sidebarLabel: JavaScript / TypeScript +title: JavaScript Клієнт для Solana +sidebarSortOrder: 2 +description: + Дізнайтеся, як взаємодіяти з Solana за допомогою клієнтської бібліотеки + JavaScript/TypeScript (@solana/web3.js). У цьому посібнику розглядаються + підключення гаманця, транзакції та взаємодія з власними програмами з + прикладами коду. +--- + +## Що таке Solana-Web3.js? + +Бібліотека Solana-Web3.js створена для забезпечення повного охоплення Solana. Ця +бібліотека побудована на основі [Solana JSON RPC API](/docs/rpc). + +Повну документацію для бібліотеки `@solana/web3.js` можна знайти +[тут](https://solana-labs.github.io/solana-web3.js/v1.x/). + +## Загальна термінологія + +| Термін | Визначення | +| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Програма | Безстанова виконувана програма, написана для інтерпретації інструкцій. Програми можуть виконувати дії на основі наданих інструкцій. | +| Інструкція | Найменша одиниця програми, яку клієнт може включити в транзакцію. Під час виконання коду інструкція може містити одну або кілька міжпрограмних викликів. | +| Транзакція | Одна або кілька інструкцій, підписаних клієнтом за допомогою одного або кількох Keypair, і виконуються атомарно з двома можливими результатами: успіх або невдача. | + +Для повного списку термінів дивіться +[Термінологія Solana](/docs/terminology.md#cross-program-invocation-cpi) + +## Початок роботи + +### Встановлення + +#### yarn + +```shell +yarn add @solana/web3.js@1 +``` + +#### npm + +```shell +npm install --save @solana/web3.js@1 +``` + +#### Пакет + +```html + + + + + +``` + +### Використання + +#### Javascript + +```javascript +const solanaWeb3 = require("@solana/web3.js"); +console.log(solanaWeb3); +``` + +#### ES6 + +```javascript +import * as solanaWeb3 from "@solana/web3.js"; +console.log(solanaWeb3); +``` + +#### Пакет для браузера + +```javascript +// solanaWeb3 надається в глобальному просторі імен за допомогою скрипта пакета +console.log(solanaWeb3); +``` + +## Швидкий старт + +### Підключення до гаманця + +Щоб користувачі могли використовувати ваш dApp або додаток у Solana, їм потрібно +отримати доступ до свого Keypair. Keypair - це приватний ключ з відповідним +відкритим ключем, який використовується для підпису транзакцій. + +Є два способи отримати Keypair: + +1. Генерація нового Keypair +2. Отримання Keypair за допомогою секретного ключа + +Ви можете отримати новий Keypair наступним чином: + +```javascript +const { Keypair } = require("@solana/web3.js"); + +let keypair = Keypair.generate(); +``` + +Це згенерує новий Keypair для користувача, який можна використовувати у вашому +додатку. + +Ви можете дозволити введення secretKey через текстове поле та отримати Keypair +за допомогою `Keypair.fromSecretKey(secretKey)`. + +```javascript +const { Keypair } = require("@solana/web3.js"); + +let secretKey = Uint8Array.from([ + 202, 171, 192, 129, 150, 189, 204, 241, 142, 71, 205, 2, 81, 97, 2, 176, 48, + 81, 45, 1, 96, 138, 220, 132, 231, 131, 120, 77, 66, 40, 97, 172, 91, 245, 84, + 221, 157, 190, 9, 145, 176, 130, 25, 43, 72, 107, 190, 229, 75, 88, 191, 136, + 7, 167, 109, 91, 170, 164, 186, 15, 142, 36, 12, 23, +]); + +let keypair = Keypair.fromSecretKey(secretKey); +``` + +Багато гаманців сьогодні дозволяють користувачам імпортувати свій Keypair за +допомогою різних розширень або веб-гаманців. Загальна рекомендація - +використовувати гаманці, а не Keypair, для підпису транзакцій. Гаманець створює +шар розділення між dApp та Keypair, забезпечуючи, що dApp ніколи не має доступу +до секретного ключа. Ви можете знайти способи підключення до зовнішніх гаманців +за допомогою бібліотеки +[wallet-adapter](https://github.com/solana-labs/wallet-adapter). + +### Створення та відправка транзакцій + +Щоб взаємодіяти з програмами на Solana, ви створюєте, підписуєте та відправляєте +транзакції до мережі. Транзакції - це колекції інструкцій з підписами. Порядок, +в якому інструкції існують у транзакції, визначає порядок їх виконання. + +Транзакція в Solana-Web3.js створюється за допомогою об'єкта +[`Transaction`](/docs/clients/javascript.md#Transaction) і додавання бажаних +повідомлень, адрес або інструкцій. + +Приклад транзакції передачі: + +```javascript +const { + Keypair, + Transaction, + SystemProgram, + LAMPORTS_PER_SOL, +} = require("@solana/web3.js"); + +let fromKeypair = Keypair.generate(); +let toKeypair = Keypair.generate(); +let transaction = new Transaction(); + +transaction.add( + SystemProgram.transfer({ + fromPubkey: fromKeypair.publicKey, + toPubkey: toKeypair.publicKey, + lamports: LAMPORTS_PER_SOL, + }), +); +``` + +Вищенаведений код створює транзакцію, готову до підпису та передачі в мережу. +Інструкція `SystemProgram.transfer` була додана до транзакції, що містить суму +lamports для відправки, а також публічні ключі `to` і `from`. + +Все, що залишилося зробити - підписати транзакцію за допомогою Keypair і +відправити її через мережу. Ви можете виконати відправку транзакції за допомогою +`sendAndConfirmTransaction`, якщо хочете сповістити користувача або зробити щось +після завершення транзакції, або використовувати `sendTransaction`, якщо не +потрібно чекати підтвердження транзакції. + +```javascript +const { + sendAndConfirmTransaction, + clusterApiUrl, + Connection, +} = require("@solana/web3.js"); + +let keypair = Keypair.generate(); +let connection = new Connection(clusterApiUrl("testnet")); + +sendAndConfirmTransaction(connection, transaction, [keypair]); +``` + +Вищенаведений код приймає `TransactionInstruction` за допомогою `SystemProgram`, +створює `Transaction` і відправляє її через мережу. Ви використовуєте +`Connection`, щоб визначити, до якої мережі Solana ви підключаєтесь, а саме +`mainnet-beta`, `testnet` або `devnet`. + +### Взаємодія з власними програмами + +Попередній розділ розглядає відправлення базових транзакцій. У Solana все, що ви +робите, взаємодіє з різними програмами, включаючи транзакцію передачі в +попередньому розділі. На момент написання програми на Solana пишуться на Rust +або C. + +Розглянемо `SystemProgram`. Сигнатура методу для виділення простору в вашому +обліковому записі в Solana на Rust виглядає так: + +```rust +pub fn allocate( + pubkey: &Pubkey, + space: u64 +) -> Instruction +``` + +У Solana, коли ви хочете взаємодіяти з програмою, ви повинні спочатку знати всі +облікові записи, з якими програма буде взаємодіяти. + +Ви завжди повинні надавати кожен обліковий запис, з яким програма буде +взаємодіяти в інструкції. Крім того, ви повинні вказати, чи є обліковий запис +`isSigner` або `isWritable`. + +У методі `allocate` вище потрібен один обліковий запис `pubkey`, а також +кількість `space` для виділення. Ми знаємо, що метод `allocate` записує в +обліковий запис, виділяючи в ньому простір, роблячи `pubkey` обов'язковим +`isWritable`. `isSigner` потрібен, коли ви вказуєте обліковий запис, який +виконує інструкцію. У цьому випадку підписувач - це обліковий запис, який +викликає виділення простору в собі. + +Давайте подивимося, як викликати цю інструкцію за допомогою solana-web3.js: + +```javascript +let keypair = web3.Keypair.generate(); +let payer = web3.Keypair.generate(); +let connection = new web3.Connection(web3.clusterApiUrl("testnet")); + +let airdropSignature = await connection.requestAirdrop( + payer.publicKey, + web3.LAMPORTS_PER_SOL, +); + +await connection.confirmTransaction({ signature: airdropSignature }); +``` + +Спочатку ми налаштовуємо Keypair і підключення, щоб у нас був обліковий запис +для виділення на тестовій мережі. Ми також створюємо Keypair для платника і +додаємо трохи SOL, щоб оплатити транзакцію виділення. + +```javascript +let allocateTransaction = new web3.Transaction({ + feePayer: payer.publicKey, +}); +let keys = [{ pubkey: keypair.publicKey, isSigner: true, isWritable: true }]; +let params = { space: 100 }; +``` + +Ми створюємо транзакцію `allocateTransaction`, об'єкти keys та params. Поле +`feePayer` є необов'язковим при створенні транзакції, воно вказує, хто оплачує +транзакцію, за замовчуванням використовується pubkey першого підписувача в +транзакції. `keys` представляє всі облікові записи, з якими функція програми +`allocate` буде взаємодіяти. Оскільки функція `allocate` також вимагає простору, +ми створили `params`, щоб його використати пізніше при виклику функції +`allocate`. + +```javascript +let allocateStruct = { + index: 8, + layout: struct([u32("instruction"), ns64("space")]), +}; +``` + +Це створено за допомогою `u32` і `ns64` з `@solana/buffer-layout` для створення +payload. Функція `allocate` приймає параметр `space`. Щоб взаємодіяти з +функцією, ми повинні надати дані у форматі Buffer. Бібліотека `buffer-layout` +допомагає з виділенням буфера та його правильним кодуванням для інтерпретації +програмами на Rust в Solana. + +Давайте розглянемо цю структуру детальніше. + +```javascript +{ + index: 8, /* <-- */ + layout: struct([ + u32('instruction'), + ns64('space'), + ]) +} +``` + +`index` встановлений у 8, тому що функція `allocate` знаходиться на 8-й позиції +у enum інструкцій для `SystemProgram`. + +```rust +/* https://github.com/solana-labs/solana/blob/21bc43ed58c63c827ba4db30426965ef3e807180/sdk/program/src/system_instruction.rs#L142-L305 */ +pub enum SystemInstruction { + /** 0 **/CreateAccount {/**/}, + /** 1 **/Assign {/**/}, + /** 2 **/Transfer {/**/}, + /** 3 **/CreateAccountWithSeed {/**/}, + /** 4 **/AdvanceNonceAccount, + /** 5 **/WithdrawNonceAccount(u64), + /** 6 **/InitializeNonceAccount(Pubkey), + /** 7 **/AuthorizeNonceAccount(Pubkey), + /** 8 **/Allocate {/**/}, + /** 9 **/AllocateWithSeed {/**/}, + /** 10 **/AssignWithSeed {/**/}, + /** 11 **/TransferWithSeed {/**/}, + /** 12 **/UpgradeNonceAccount, +} +``` + +Далі `u32('instruction')`. + +```javascript +{ + index: 8, + layout: struct([ + u32('instruction'), /* <-- */ + ns64('space'), + ]) +} +``` + +`layout` у структурі allocate завжди має мати `u32('instruction')` першим при +використанні для виклику інструкції. + +```javascript +{ + index: 8, + layout: struct([ + u32('instruction'), + ns64('space'), /* <-- */ + ]) +} +``` + +`ns64('space')` - це аргумент для функції `allocate`. Ви можете бачити, що в +оригінальній функції `allocate` на Rust, space мав тип `u64`. `u64` є 64-бітовим +unsigned integer. У Javascript за замовчуванням підтримуються тільки 53-бітові +числа. `ns64` з `@solana/buffer-layout` допомагає з конвертацією типів між Rust +і Javascript. Ви можете знайти більше конвертацій типів між Rust і Javascript на +[solana-labs/buffer-layout](https://github.com/solana-labs/buffer-layout). + +```javascript +let data = Buffer.alloc(allocateStruct.layout.span); +let layoutFields = Object.assign({ instruction: allocateStruct.index }, params); +allocateStruct.layout.encode(layoutFields, data); +``` + +Використовуючи створений раніше bufferLayout, ми можемо виділити буфер даних. +Потім ми присвоюємо наші params `{ space: 100 }`, щоб вони правильно відповідали +макету, і кодуємо їх у буфер даних. Тепер дані готові для відправлення до +програми. + +```javascript +allocateTransaction.add( + new web3.TransactionInstruction({ + keys, + programId: web3.SystemProgram.programId, + data, + }), +); + +await web3.sendAndConfirmTransaction(connection, allocateTransaction, [ + payer, + keypair, +]); +``` + +Нарешті, ми додаємо інструкцію транзакції з усіма ключами облікових записів, +платником, даними та programId і передаємо транзакцію до мережі. + +Повний код можна знайти нижче. + +```javascript +const { struct, u32, ns64 } = require("@solana/buffer-layout"); +const { Buffer } = require("buffer"); +const web3 = require("@solana/web3.js"); + +let keypair = web3.Keypair.generate(); +let payer = web3.Keypair.generate(); + +let connection = new web3.Connection(web3.clusterApiUrl("testnet")); + +let airdropSignature = await connection.requestAirdrop( + payer.publicKey, + web3.LAMPORTS_PER_SOL, +); + +await connection.confirmTransaction({ signature: airdropSignature }); + +let allocateTransaction = new web3.Transaction({ + feePayer: payer.publicKey, +}); +let keys = [{ pubkey: keypair.publicKey, isSigner: true, isWritable: true }]; +let params = { space: 100 }; + +let allocateStruct = { + index: 8, + layout: struct([u32("instruction"), ns64("space")]), +}; + +let data = Buffer.alloc(allocateStruct.layout.span); +let layoutFields = Object.assign({ instruction: allocateStruct.index }, params); +allocateStruct.layout.encode(layoutFields, data); + +allocateTransaction.add( + new web3.TransactionInstruction({ + keys, + programId: web3.SystemProgram.programId, + data, + }), +); + +await web3.sendAndConfirmTransaction(connection, allocateTransaction, [ + payer, + keypair, +]); +``` diff --git a/docs/locales/uk/clients/rust.md b/docs/locales/uk/clients/rust.md new file mode 100644 index 000000000..b9037668c --- /dev/null +++ b/docs/locales/uk/clients/rust.md @@ -0,0 +1,52 @@ +--- +sidebarLabel: Rust +title: Rust Клієнт для Solana +sidebarSortOrder: 1 +description: Дізнайтеся, як використовувати Rust пакети для розробки в Solana. +--- + +Rust пакети для Solana +[опубліковані на crates.io](https://crates.io/search?q=solana-) і доступні на +[docs.rs](https://docs.rs/releases/search?query=solana-) з префіксом `solana-`. + + + +Щоб швидко почати розробку в Solana і створити вашу першу програму на Rust, +ознайомтеся з цими детальними посібниками для швидкого старту: + +- [Створіть і розгорніть вашу першу програму Solana, використовуючи тільки ваш браузер](/content/guides/getstarted/hello-world-in-your-browser.md). + Інсталяція не потрібна. +- [Налаштуйте ваше локальне середовище](/docs/uk/intro/installation) і + використовуйте локальний тестовий валідатор. + + + +## Rust Пакети + +Нижче наведено найважливіші та найчастіше використовувані Rust пакети для +розробки в Solana: + +- [`solana-program`] — Імпортується програмами, що працюють у Solana, і + компілюється до SBF. Цей пакет містить багато фундаментальних типів даних і + реекспортується з [`solana-sdk`], який не можна імпортувати у програму Solana. + +- [`solana-sdk`] — Базовий SDK для роботи поза мережею, реекспортує + [`solana-program`] і додає більше API на додаток до цього. Більшість програм + Solana, що не працюють у мережі, імпортують цей пакет. + +- [`solana-client`] — Для взаємодії з вузлом Solana через + [JSON RPC API](/docs/uk/rpc). + +- [`solana-cli-config`] — Завантаження та збереження конфігураційного + файлу Solana CLI. + +- [`solana-clap-utils`] — Рутини для налаштування CLI, використовуючи + [`clap`], як у основному CLI Solana. Включає функції для завантаження всіх + типів підписантів, підтримуваних CLI. + +[`solana-program`]: https://docs.rs/solana-program +[`solana-sdk`]: https://docs.rs/solana-sdk +[`solana-client`]: https://docs.rs/solana-client +[`solana-cli-config`]: https://docs.rs/solana-cli-config +[`solana-clap-utils`]: https://docs.rs/solana-clap-utils +[`clap`]: https://docs.rs/clap diff --git a/docs/locales/uk/core/accounts.md b/docs/locales/uk/core/accounts.md new file mode 100644 index 000000000..ab7f7bd41 --- /dev/null +++ b/docs/locales/uk/core/accounts.md @@ -0,0 +1,206 @@ +--- +sidebarSortOrder: 1 +sidebarLabel: Модель облікових записів Solana +title: Модель облікових записів Solana +description: + Дізнайтеся про модель облікових записів Solana, включаючи те, як облікові + записи зберігають дані і програми, механіку оренди, власність облікових + записів і взаємозв'язок між програмами та обліковими записами даних. + Зрозумійте основні концепції системи зберігання ключ-значення Solana. +--- + +У Solana всі дані зберігаються в так званих "облікових записах". Спосіб +організації даних у Solana нагадує +[сховище ключ-значення](https://uk.wikipedia.org/wiki/%D0%91%D0%B0%D0%B7%D0%B0_%D0%B4%D0%B0%D0%BD%D0%B8%D1%85_%C2%AB%D0%BA%D0%BB%D1%8E%D1%87%E2%80%94%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%BD%D1%8F%C2%BB), +де кожен запис у базі даних називається "обліковим записом". + +![Облікові записи](/assets/docs/core/accounts/accounts.svg) + +## Основні моменти + +- Облікові записи можуть зберігати до 10 МБ даних, які можуть складатися з + виконуваного коду програми або стану програми. + +- Облікові записи потребують застави в SOL, пропорційної обсягу збережених + даних, яка повністю повертається при закритті облікового запису. + +- Кожен обліковий запис має "власника" програми. Тільки програма, яка володіє + обліковим записом, може змінювати його дані або знімати баланс лампортів. + Однак будь-хто може збільшити баланс. + +- Програми (смартконтракти) є безстанними обліковими записами, які зберігають + виконуваний код. + +- Облікові записи даних створюються програмами для зберігання і керування станом + програми. + +- Вбудовані програми - це вбудовані програми, які включені у середовище + виконання Solana. + +- Системні облікові записи - це спеціальні облікові записи, які зберігають стан + кластера мережі. + +## Обліковий запис + +Кожен обліковий запис ідентифікується його унікальною адресою, представленою у +форматі 32 байт як [Ed25519](https://ed25519.cr.yp.to/) `PublicKey`. Ви можете +вважати адресу унікальним ідентифікатором облікового запису. + +![Адреса облікового запису](/assets/docs/core/accounts/account-address.svg) + +Цей зв'язок між обліковим записом та його адресою можна розглядати як пару +ключ-значення, де адреса є ключем для пошуку відповідних даних облікового запису +в ланцюжку. + +### AccountInfo + +Облікові записи мають +[максимальний розмір у 10 МБ](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/sdk/program/src/system_instruction.rs#L85) +(10 мегабайт), а дані, що зберігаються в кожному обліковому записі Solana, мають +наступну структуру, відому як +[AccountInfo](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/sdk/program/src/account_info.rs#L19). + +![AccountInfo](/assets/docs/core/accounts/accountinfo.svg) + +`AccountInfo` для кожного облікового запису включає наступні поля: + +- `data`: Масив байтів, який зберігає стан облікового запису. Якщо обліковий + запис є програмою (смартконтрактом), це поле зберігає виконуваний код + програми. Це поле часто називають "даними облікового запису". +- `executable`: Булевий прапорець, який вказує, чи є обліковий запис програмою. +- `lamports`: Числове представлення балансу облікового запису в + [лампортах](/docs/terminology.md#lamport), найменшій одиниці SOL (1 SOL = 1 + мільярд лампортів). +- `owner`: Вказує публічний ключ (Program ID) програми, яка володіє обліковим + записом. + +Як ключова частина моделі облікових записів Solana, кожен обліковий запис у +Solana має визначеного "власника", а саме програму. Тільки програма, зазначена +як власник облікового запису, може змінювати дані, що зберігаються в обліковому +записі, або знімати баланс лампортів. Важливо зазначити, що, хоча тільки власник +може знімати баланс, будь-хто може збільшити баланс. + +> Для зберігання даних у ланцюжку потрібно передати певну кількість SOL до +> облікового запису. Кількість, що передається, пропорційна розміру даних, що +> зберігаються в обліковому записі. Ця концепція зазвичай називається "орендою". +> Однак, ви можете розглядати "оренду" швидше як "депозит", оскільки SOL, +> виділені для облікового запису, можуть бути повністю відновлені при закритті +> облікового запису. + +## Вбудовані програми + +Solana містить невелику кількість вбудованих програм, які є частиною реалізації +валідатора і забезпечують різні основні функціональності для мережі. Ви можете +знайти повний список вбудованих програм +[тут](https://docs.anza.xyz/runtime/programs). + +При розробці користувацьких програм на Solana ви часто будете взаємодіяти з +двома вбудованими програмами: Системною Програмою і Завантажувачем BPF. + +### Системна Програма + +За замовчуванням усі нові облікові записи належать +[Системній Програмі](https://github.com/solana-labs/solana/tree/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/programs/system/src). +Системна Програма виконує кілька ключових завдань, таких як: + +- [Створення нового облікового запису](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/programs/system/src/system_processor.rs#L145): + Тільки Системна Програма може створювати нові облікові записи. +- [Виділення простору](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/programs/system/src/system_processor.rs#L70): + Встановлює обсяг пам'яті для поля даних кожного облікового запису. +- [Призначення власника програми](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/programs/system/src/system_processor.rs#L112): + Після створення облікового запису Системною Програмою вона може перепризначити + власника програми іншому обліковому запису програми. Це спосіб, за яким + користувацькі програми беруть у власність нові облікові записи, створені + Системною Програмою. + +У Solana "гаманець" просто є обліковим записом, який належить Системній +Програмі. Баланс лампортів у гаманці є кількістю SOL, що належать обліковому +запису. + +![Системний Обліковий Запис](/assets/docs/core/accounts/system-account.svg) + +> Тільки облікові записи, що належать Системній Програмі, можуть +> використовуватися як платники комісій за транзакції. + +### Завантажувач BPF + +[Завантажувач BPF](https://github.com/solana-labs/solana/tree/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/programs/bpf_loader/src) +є програмою, яка призначена як "власник" усіх інших програм у мережі, крім +Вбудованих Програм. Він відповідає за розгортання, оновлення та виконання +користувацьких програм. + +## Системні Облікові Записи + +Системні облікові записи - це спеціальні облікові записи, розташовані за +попередньо визначеними адресами, які надають доступ до даних про стан кластера +мережі. Ці облікові записи динамічно оновлюються даними про кластер мережі. Ви +можете знайти повний список Системних Облікових Записів +[тут](https://docs.anza.xyz/runtime/sysvars). + +## Користувацькі Програми + +У Solana "смартконтракти" називаються [програмами](/docs/core/programs.md). +Програма є обліковим записом, який містить виконуваний код, і позначається +прапорцем "виконуваний", який встановлено в значення "true". + +Для детального пояснення процесу розгортання програми, зверніться до сторінки +[Розгортання Програм](/docs/programs/deploying.md) цієї документації. + +### Обліковий Запис Програми + +Коли нові програми +[розгортаються](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/programs/bpf_loader/src/lib.rs#L498) +на Solana, технічно створюються три окремі облікові записи: + +- **Обліковий Запис Програми**: Основний обліковий запис, який представляє + програму в ланцюжку. Цей обліковий запис зберігає адресу виконуваного + облікового запису даних (який зберігає зкомпільований код програми) і право на + оновлення програми (адреса, яка має дозвіл на внесення змін до програми). +- **Виконуваний Обліковий Запис Програми**: Обліковий запис, який містить + виконуваний байт-код програми. +- **Буферний Обліковий Запис**: Тимчасовий обліковий запис, який зберігає + байт-код під час активного розгортання або оновлення програми. Після + завершення процесу дані передаються до Виконуваного Облікового Запису + Програми, а буферний обліковий запис закривається. + +Наприклад, ось посилання на Solana Explorer для Програмного Розширення Токенів +[Обліковий Запис Програми](https://explorer.solana.com/address/TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb) +і його відповідний +[Виконуваний Обліковий Запис Програми](https://explorer.solana.com/address/DoU57AYuPFu2QU514RktNPG22QhApEjnKxnBcu4BHDTY). + +![Облікові Записи Програми та Виконуваних Даних](/assets/docs/core/accounts/program-account-expanded.svg) + +Для простоти ви можете вважати "Обліковий Запис Програми" як саму програму. + +![Обліковий Запис Програми](/assets/docs/core/accounts/program-account-simple.svg) + +> Адреса "Облікового Запису Програми" зазвичай називається "ID Програми", який +> використовується для виклику програми. + +### Обліковий Запис Даних + +Програми Solana є "безстанними", тобто облікові записи програм містять лише +виконуваний байт-код програми. Для зберігання та модифікації додаткових даних +необхідно створювати нові облікові записи. Ці облікові записи зазвичай +називаються "обліковими записами даних". + +Облікові записи даних можуть зберігати будь-які довільні дані, визначені в коді +програми-власника. + +![Обліковий Запис Даних](/assets/docs/core/accounts/data-account.svg) + +Зверніть увагу, що тільки +[Системна Програма](/docs/core/accounts.md#system-program) може створювати нові +облікові записи. Після створення облікового запису Системною Програмою вона може +потім передати власність нового облікового запису іншій програмі. + +Іншими словами, створення облікового запису даних для користувацької програми +вимагає двох кроків: + +1. Виклик Системної Програми для створення облікового запису, яка потім передає + власність користувацькій програмі +2. Виклик користувацької програми, яка тепер володіє обліковим записом, для + ініціалізації даних облікового запису, як це визначено в коді програми + +Цей процес створення облікового запису даних часто абстрагується як єдиний крок, +але корисно розуміти підлеглий процес. diff --git a/docs/locales/uk/core/clusters.md b/docs/locales/uk/core/clusters.md new file mode 100644 index 000000000..b2a5944fe --- /dev/null +++ b/docs/locales/uk/core/clusters.md @@ -0,0 +1,174 @@ +--- +sidebarLabel: Кластери та точки доступу RPC +title: Кластери та публічні точки доступу RPC +sidebarSortOrder: 8 +description: + Дізнайтеся про кластери мережі Solana (Devnet, Testnet і Mainnet Beta), їхні + публічні точки доступу RPC, обмеження швидкості та випадки використання. + Дізнайтеся, як підключатися до різних мереж Solana для розробки, тестування та + виробничого середовища. +--- + +Блокчейн Solana має кілька різних груп валідаторів, відомих як +[Кластери](/docs/uk/core/clusters.md). Кожен з них обслуговує різні цілі в межах +загальної екосистеми та містить виділені вузли API для виконання +[JSON-RPC](/docs/uk/rpc/index.mdx) запитів для своїх відповідних кластерів. + +Індивідуальні вузли в межах кластера належать та управляються третіми сторонами, +з публічною точкою доступу, доступною для кожного. + +## Публічні точки доступу RPC Solana + +Організація Solana Labs керує публічною точкою доступу RPC для кожного кластера. +Кожна з цих публічних точок доступу має обмеження швидкості, але доступна для +користувачів та розробників для взаємодії з блокчейном Solana. + +> Обмеження швидкості публічних точок доступу можуть змінюватися. Зазначені +> обмеження швидкості в цьому документі можуть бути не найактуальнішими. + +### Використання експлорерів з різними кластерами + +Багато популярних експлорерів блокчейну Solana підтримують вибір будь-якого +кластера, часто дозволяючи досвідченим користувачам додавати користувацьку/ +приватну точку доступу RPC. + +Прикладами таких експлорерів є: + +- [http://explorer.solana.com/](https://explorer.solana.com/). +- [http://solana.fm/](https://solana.fm/). +- [http://solscan.io/](https://solscan.io/). +- [http://solanabeach.io/](http://solanabeach.io/). +- [http://validators.app/](http://validators.app/). + +## Основні відомості + +- Mainnet: Живе виробниче середовище для розгорнутих додатків. +- Devnet: Тестування з публічним доступом для розробників, які експериментують + зі своїми додатками. +- Testnet: Стрес-тестування для оновлень мережі та продуктивності валідаторів. + +**Приклади використання**: Можливо, ви захочете налагодити нову програму на +Devnet або перевірити метрики продуктивності на Testnet перед розгортанням на +Mainnet. + +| **Кластер** | **Точка доступу** | **Призначення** | **Примітки** | +| ----------- | ------------------------------------- | ------------------------------- | ------------------------------- | +| Mainnet | `https://api.mainnet-beta.solana.com` | Живе виробниче середовище | Потребує SOL для транзакцій | +| Devnet | `https://api.devnet.solana.com` | Публічне тестування та розробка | Безкоштовний SOL для тестування | +| Testnet | `https://api.testnet.solana.com` | Тестування валідаторів | Може мати періодичні простої | + +## Devnet + +Devnet слугує тестовим майданчиком для будь-кого, хто хоче ознайомитися з Solana +як користувач, власник токенів, розробник додатків або валідатор. + +- Розробники додатків повинні орієнтуватися на Devnet. +- Потенційні валідатори повинні спочатку орієнтуватися на Devnet. +- Основні відмінності між Devnet і Mainnet Beta: + - Токени Devnet **не реальні**. + - Devnet включає крани для отримання токенів для тестування додатків. + - Devnet може піддаватися скиданням журналу. + - Devnet зазвичай працює на тій самій гілці випуску програмного забезпечення, + що й Mainnet Beta, але може працювати на новішій мінорній версії. +- Точка доступу Gossip для Devnet: `entrypoint.devnet.solana.com:8001` + +### Точка доступу Devnet + +- `https://api.devnet.solana.com` - єдиний вузол API, розміщений Solana Labs; з + обмеженнями швидкості + +#### Приклад конфігурації командного рядка `solana` + +Щоб підключитися до кластеру `devnet` за допомогою CLI Solana: + +```shell +solana config set --url https://api.devnet.solana.com +``` + +### Обмеження швидкості Devnet + +- Максимальна кількість запитів на 10 секунд на IP: 100 +- Максимальна кількість запитів на 10 секунд на IP для одного RPC: 40 +- Максимальна кількість одночасних з'єднань на IP: 40 +- Максимальна швидкість з'єднань на 10 секунд на IP: 40 +- Максимальна кількість даних на 30 секунд: 100 МБ + +## Testnet + +Testnet - це місце, де основні учасники Solana стрес-тестують функції останніх +випусків у живому кластері, особливо зосереджуючись на продуктивності мережі, +стабільності та поведінці валідаторів. + +- Токени Testnet **не реальні**. +- Testnet може піддаватися скиданням журналу. +- Testnet включає крани для отримання токенів для тестування додатків. +- Testnet зазвичай працює на новішій гілці випуску програмного забезпечення, ніж + Devnet і Mainnet Beta. +- Точка доступу Gossip для Testnet: `entrypoint.testnet.solana.com:8001` + +### Точка доступу Testnet + +- `https://api.testnet.solana.com` - єдиний вузол API, розміщений Solana Labs; з + обмеженнями швидкості + +#### Приклад конфігурації командного рядка `solana` + +Щоб підключитися до кластеру `testnet` за допомогою CLI Solana: + +```shell +solana config set --url https://api.testnet.solana.com +``` + +### Обмеження швидкості Testnet + +- Максимальна кількість запитів на 10 секунд на IP: 100 +- Максимальна кількість запитів на 10 секунд на IP для одного RPC: 40 +- Максимальна кількість одночасних з'єднань на IP: 40 +- Максимальна швидкість з'єднань на 10 секунд на IP: 40 +- Максимальна кількість даних на 30 секунд: 100 МБ + +## Mainnet beta + +Безперешкодний, постійний кластер для користувачів Solana, розробників, +валідаторів та власників токенів. + +- Токени, випущені на Mainnet Beta, є **реальними** SOL. +- Точка доступу Gossip для Mainnet Beta: + `entrypoint.mainnet-beta.solana.com:8001` + +### Точка доступу Mainnet beta + +- `https://api.mainnet-beta.solana.com` - кластер вузлів API, розміщених Solana + Labs, із підтримкою балансувальника навантаження; з обмеженнями швидкості + +#### Приклад конфігурації командного рядка `solana` + +Щоб підключитися до кластеру `mainnet-beta` за допомогою CLI Solana: + +```shell +solana config set --url https://api.mainnet-beta.solana.com +``` + +### Обмеження швидкості Mainnet beta + +- Максимальна кількість запитів на 10 секунд на IP: 100 +- Максимальна кількість запитів на 10 секунд на IP для одного RPC: 40 +- Максимальна кількість одночасних з'єднань на IP: 40 +- Максимальна швидкість з'єднань на 10 секунд на IP: 40 +- Максимальна кількість даних на 30 секунд: 100 МБ + +> Публічні точки доступу RPC не призначені для виробничих додатків. Будь ласка, +> використовуйте виділені/приватні сервери RPC під час запуску додатка, випуску +> NFT тощо. Публічні сервіси піддаються зловживанням, і обмеження швидкості +> можуть змінюватися без попередження. Також, вебсайти з високим трафіком можуть +> бути заблоковані без попередження. + +## Загальні HTTP-коди помилок + +- 403 -- Ваша IP-адреса або вебсайт було заблоковано. Настав час запустити + власні сервери RPC або знайти приватний сервіс. +- 429 -- Ваша IP-адреса перевищує обмеження швидкості. Зменшіть швидкість! + Використовуйте + [Retry-After](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After) + HTTP-заголовок відповіді, щоб визначити, як довго потрібно чекати перед + повторною спробою. diff --git a/docs/locales/uk/core/cpi.md b/docs/locales/uk/core/cpi.md new file mode 100644 index 000000000..a15da2bb8 --- /dev/null +++ b/docs/locales/uk/core/cpi.md @@ -0,0 +1,136 @@ +--- +title: Виклики між програмами (CPI) +sidebarLabel: Виклики між програмами +sidebarSortOrder: 6 +description: + Дізнайтеся про виклики між програмами (CPI) у Solana - як програми можуть + викликати інструкції інших програм, обробляти підписантів PDA і складати + функціональність у мережі Solana. +--- + +Виклик між програмами (CPI) відбувається, коли одна програма викликає інструкції +іншої програми. Цей механізм дозволяє складати програми Solana. + +Інструкції можна уявити як API-методи, які програма надає мережі, а CPI - це +виклик одного API-методу іншим API-методом. + +![Виклик між програмами](/assets/docs/core/cpi/cpi.svg) + +Коли програма ініціює виклик між програмами (CPI) до іншої програми: + +- Привілеї підпису від початкової транзакції, що викликає програму (A), + розширюються на програму-отримувача (B). +- Програма-отримувач (B) може здійснювати подальші CPI до інших програм до + максимального рівня глибини 4 (наприклад, B->C, C->D). +- Програми можуть "підписувати" від імені [PDA](/docs/core/pda.md), що створені + з їхнього ID програми. + +> У середовищі виконання програм Solana визначено константу під назвою +> [`max_invoke_stack_height`](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/program-runtime/src/compute_budget.rs#L31-L35), +> яка має значення +> [5](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/program-runtime/src/compute_budget.rs#L138). +> Це обмеження встановлює максимальну висоту стеку викликів інструкцій програми. +> Висота стеку починається з 1 для інструкцій транзакції, збільшується на 1 +> кожного разу, коли програма викликає іншу інструкцію. Це ефективно обмежує +> глибину викликів для CPI до 4. + +## Основні моменти + +- CPI дозволяє інструкціям програми Solana безпосередньо викликати інструкції + іншої програми. + +- Привілеї підпису від програми-виклику розширюються на програму-отримувача. + +- Під час здійснення CPI програми можуть "підписувати" від імені PDA, створених + із їхнього власного ID програми. + +- Програма-отримувач може здійснювати додаткові CPI до інших програм до + максимальної глибини 4. + +## Як написати CPI + +Написання інструкції для CPI слідує тій самій схемі, що й побудова +[інструкції](/docs/core/transactions.md#instruction) для додавання до +транзакції. Кожна інструкція CPI повинна зазначати таку інформацію: + +- **Адреса програми**: Вказує програму, яка викликається +- **Облікові записи**: Перераховує кожен обліковий запис, з якого інструкція + читає або в який записує, включаючи інші програми +- **Дані інструкції**: Вказує, яку інструкцію у програмі викликати, а також + будь-які додаткові дані, необхідні для інструкції (аргументи функції) + +Залежно від програми, до якої здійснюється виклик, можуть бути доступні crates +із допоміжними функціями для створення інструкції. Програми потім виконують CPI +за допомогою однієї з наступних функцій з crate `solana_program`: + +- `invoke` - використовується, коли немає підписантів PDA +- `invoke_signed` - використовується, коли програма-викликач повинна підписати + за допомогою PDA, створеного з її ID програми + +### Базовий CPI + +Функція +[`invoke`](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/sdk/program/src/program.rs#L132) +використовується під час здійснення CPI, який не потребує підписантів PDA. Під +час здійснення CPI підписанти, надані програмі-виклику, автоматично розширюються +на програму-отримувача. + +```rust +pub fn invoke( + instruction: &Instruction, + account_infos: &[AccountInfo<'_>] +) -> Result<(), ProgramError> +``` + +Ось приклад програми на +[Solana Playground](https://beta.solpg.io/github.com/ZYJLiu/doc-examples/tree/main/cpi-invoke), +яка здійснює CPI за допомогою функції `invoke` для виклику інструкції передачі в +Системній Програмі. Ви також можете ознайомитися з +[Базовим посібником CPI](/content/guides/getstarted/how-to-cpi.md) для +додаткової інформації. + +### CPI з підписантом PDA + +Функція +[`invoke_signed`](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/sdk/program/src/program.rs#L247) +використовується під час здійснення CPI, який потребує підписантів PDA. Насіння, +що використовується для створення підписаних PDA, передається у функцію +`invoke_signed` як `signer_seeds`. + +Ви можете ознайомитися з сторінкою +[Програмно Створені Адреси (PDA)](/docs/core/pda.md) для деталей про те, як PDA +створюються. + +```rust +pub fn invoke_signed( + instruction: &Instruction, + account_infos: &[AccountInfo<'_>], + signers_seeds: &[&[&[u8]]] +) -> Result<(), ProgramError> +``` + +Середовище виконання використовує привілеї, надані програмі-виклику, щоб +визначити, які привілеї можуть бути розширені на програму-отримувача. У цьому +контексті привілеї стосуються підписантів і облікових записів із правом запису. +Наприклад, якщо інструкція, яку обробляє програма-викликач, містить підписанта +або обліковий запис із правом запису, то програма-викликач може викликати +інструкцію, яка також містить цього підписанта та/або обліковий запис із правом +запису. + +Хоча PDA не мають [приватних ключів](/docs/core/pda.md#what-is-a-pda), вони все +одно можуть діяти як підписант в інструкції через CPI. Щоб підтвердити, що PDA +створений із програми, що викликає, необхідно включити насіння, використане для +створення PDA, як `signers_seeds`. + +Коли CPI обробляється, середовище виконання Solana +[викликає внутрішньо `create_program_address`](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/programs/bpf_loader/src/syscalls/cpi.rs#L550) +за допомогою `signers_seeds` і `program_id` програми-виклику. Якщо виявлено +дійсний PDA, адресу додають +[як дійсного підписанта](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/programs/bpf_loader/src/syscalls/cpi.rs#L552). + +Ось приклад програми на +[Solana Playground](https://beta.solpg.io/github.com/ZYJLiu/doc-examples/tree/main/cpi-invoke-signed), +яка здійснює CPI за допомогою функції `invoke_signed` для виклику інструкції +передачі в Системній Програмі з підписантом PDA. Ви можете ознайомитися з +[Посібником CPI з підписантом PDA](/content/guides/getstarted/how-to-cpi-with-signer.md) +для додаткової інформації. diff --git a/docs/locales/uk/core/fees.md b/docs/locales/uk/core/fees.md new file mode 100644 index 000000000..87f200807 --- /dev/null +++ b/docs/locales/uk/core/fees.md @@ -0,0 +1,501 @@ +--- +title: Плата на Solana +sidebarSortOrder: 3 +description: + Дізнайтеся про структуру плати на Solana, включаючи транзакційні збори, + пріоритизаційні збори та витрати на оренду. Зрозумійте, як обчислюється, + збирається та розподіляється плата в мережі. +keywords: + - плата за інструкцію + - плата за обробку + - плата за збереження + - оренда + - газ + - гвей +altRoutes: + - /docs/uk/core/rent + - /docs/uk/intro/rent + - /docs/uk/intro/transaction_fees + - /docs/uk/intro/transaction-fees + - /docs/uk/core/runtime +--- + +Блокчейн Solana має кілька типів плати та витрат, які виникають під час +використання мережі без дозволу. Вони поділяються на кілька специфічних типів: + +- **Транзакційні збори** — плата за обробку транзакцій/інструкцій валідаторами. +- **Пріоритизаційні збори** — додаткова плата для підвищення порядку обробки + транзакцій. +- **Оренда** — утримуваний баланс для збереження даних в ончейні. + +## Транзакційні збори + +Мала плата, яка сплачується за обробку логіки (інструкції) у програмі в ончейні +на блокчейні Solana, називається "_транзакційною платою_". + +Кожна [транзакція](/docs/uk/core/transactions.md#transaction), яка містить одну +або більше [інструкцій](/docs/uk/core/transactions.md#instruction), надсилається +через мережу, де її обробляє поточний лідер-валідатор. Після підтвердження як +глобальної транзакції ця "транзакційна плата" сплачується мережі для підтримки +економічної моделі блокчейна Solana. + +> Транзакційні збори відрізняються від плати за збереження даних в обліковому +> записі, відомої як [оренда](#rent). Транзакційні збори сплачуються за обробку +> інструкцій у мережі Solana, а депозит оренди утримується в обліковому записі +> для збереження даних в блокчейні та може бути повернутий. + +На даний момент базова транзакційна плата в Solana встановлена на рівні 5000 +лампортів за підпис. На додаток до цієї базової плати, можуть бути додані +додаткові [пріоритизаційні збори](#prioritization-fee). + +### Навіщо сплачувати транзакційні збори? + +Транзакційні збори пропонують багато переваг у економічній моделі Solana, +зокрема вони: + +- Забезпечують компенсацію мережі валідаторів за витрачені ресурси CPU/GPU для + обробки транзакцій. +- Зменшують спам у мережі, запроваджуючи реальну вартість транзакцій. +- Забезпечують довгострокову економічну стабільність мережі через протокольно + захоплену мінімальну плату за транзакцію. + +### Основи економічної моделі + +Багато блокчейн-мереж (включаючи Bitcoin та Ethereum) покладаються на інфляційні +"протокольні нагороди" для короткострокової підтримки безпеки мережі. У +довгостроковій перспективі ці мережі все більше покладаються на "транзакційні +збори" для підтримки безпеки. + +Те саме стосується Solana. Зокрема: + +- Фіксована частка (спочатку 50%) кожної транзакційної плати "спалюється" + (знищується), решта надходить до поточного + [лідера](/docs/uk/terminology.md#leader), який обробляє транзакцію. +- Запланована глобальна інфляційна ставка забезпечує джерело + [нагород](https://docs.anza.xyz/implemented-proposals/staking-rewards), які + розподіляються серед [валідаторів Solana](https://docs.anza.xyz/operations). + +### Збір плати + +Транзакції повинні мати щонайменше один обліковий запис, який підписав +транзакцію та може бути змінений. Ці "записувані підписуючі облікові записи" +серіалізуються першими у списку облікових записів, і перший з них завжди +використовується як "платник плати". + +Перед обробкою будь-яких інструкцій транзакції баланс облікового запису платника +плати +[вираховується](https://github.com/anza-xyz/agave/blob/b7bbe36918f23d98e2e73502e3c4cba78d395ba9/runtime/src/bank.rs#L4045-L4064) +для оплати транзакційних зборів. Якщо баланс платника плати недостатній для +покриття зборів, обробка транзакції припиняється і вона визнається невдалою. + +Якщо баланс був достатнім, плата буде вирахувана, і виконання інструкцій +транзакції почнеться. Якщо будь-яка з інструкцій призведе до помилки, обробка +транзакції буде припинена, і зрештою вона буде записана як невдала транзакція в +книзі Solana. Плата все одно буде зібрана за ці невдалі транзакції. + +Якщо будь-яка з інструкцій повертає помилку або порушує обмеження часу +виконання, всі зміни облікових записів **_крім_** вирахування транзакційної +плати будуть скасовані. Це тому, що мережа валідаторів вже витратила +обчислювальні ресурси для збору транзакцій та початку їх обробки. + +### Розподіл плати + +Транзакційні збори +[частково спалюються](https://github.com/anza-xyz/agave/blob/b7bbe36918f23d98e2e73502e3c4cba78d395ba9/runtime/src/bank/fee_distribution.rs#L55-L64), +а решта зборів збираються валідатором, який створив блок, у якому включені +відповідні транзакції. Зокрема, +[50% спалюються](https://github.com/anza-xyz/agave/blob/b7bbe36918f23d98e2e73502e3c4cba78d395ba9/sdk/program/src/fee_calculator.rs#L79), +а +[50% розподіляються](https://github.com/anza-xyz/agave/blob/e621336acad4f5d6e5b860eaa1b074b01c99253c/runtime/src/bank/fee_distribution.rs#L58-L62) +валідатору, який створив блок. + +### Чому спалюються частина зборів? + +Як згадано вище, фіксована частка кожної транзакційної плати "спалюється" +(знищується). Це зроблено для зміцнення економічної цінності SOL і підтримки +безпеки мережі. На відміну від системи, де всі транзакційні збори повністю +спалюються, лідери все ще мають стимул включати якомога більше транзакцій у свої +слоти (можливість створити блок). + +Спалені збори також можуть допомогти запобігти зловмисним валідаторам у +цензуруванні транзакцій через врахування в +[виборі форку](/docs/uk/terminology.md#fork). + +#### Приклад атаки: + +У випадку +[форку Proof of History (PoH)](/docs/uk/terminology.md#proof-of-history-poh) з +лідером, що займається цензурою або зловживанням: + +- через втрати зборів, що виникають через цензуру, очікується, що загальні + збори, які будуть спалені, будуть **_меншими_**, ніж у порівнянному чесному + форку; +- якщо лідер, який займається цензурою, хоче компенсувати ці втрачені + протокольні збори, він повинен буде самостійно замінити спалені збори на + своєму форку; +- таким чином, потенційно зменшуючи стимул до цензури в першу чергу. + +### Обчислення транзакційних зборів + +Повна плата за конкретну транзакцію розраховується на основі двох основних +частин: + +- Статично встановлена базова плата за підпис, і +- Обчислювальні ресурси, використані під час транзакції, виміряні у + "[обчислювальних одиницях](/docs/uk/terminology.md#compute-units)". + +Оскільки кожна транзакція може вимагати різної кількості обчислювальних +ресурсів, кожній транзакції виділяється максимальна кількість _обчислювальних +одиниць_ у рамках "обчислювального бюджету". + +## Обчислювальний бюджет + +Щоб запобігти зловживанню обчислювальними ресурсами, кожній транзакції +виділяється "обчислювальний бюджет". Цей бюджет визначає: + +- обчислювальні витрати, пов'язані з різними типами операцій, які може + виконувати транзакція (обчислювальні одиниці, спожиті на операцію), +- максимальну кількість обчислювальних одиниць, які може спожити транзакція + (ліміт обчислювальних одиниць), +- та операційні межі, яких має дотримуватися транзакція (наприклад, ліміти + розміру даних облікового запису). + +Коли транзакція вичерпує свій обчислювальний бюджет (вичерпання обчислювального +бюджету) або перевищує межі, наприклад, намагається перевищити +[максимальну глибину стеку викликів](https://github.com/anza-xyz/agave/blob/b7bbe36918f23d98e2e73502e3c4cba78d395ba9/program-runtime/src/compute_budget.rs#L138) +або +[максимальний розмір завантажених даних облікового запису](#accounts-data-size-limit), +виконання транзакції припиняється, і повертається помилка. Це призводить до +невдалої транзакції та жодних змін стану (окрім збору плати за транзакцію). + +### Ліміт розміру даних облікового запису + +Транзакція може встановлювати максимальну кількість байтів даних облікового +запису, які їй дозволено завантажувати, включивши інструкцію +`SetLoadedAccountsDataSizeLimit` (не перевищуючи абсолютний максимум часу +виконання). Якщо `SetLoadedAccountsDataSizeLimit` не надано, транзакція за +замовчуванням використовує значення часу виконання +[`MAX_LOADED_ACCOUNTS_DATA_SIZE_BYTES`](https://github.com/anza-xyz/agave/blob/b7bbe36918f23d98e2e73502e3c4cba78d395ba9/program-runtime/src/compute_budget_processor.rs#L137-L139). + +Функцію `ComputeBudgetInstruction::set_loaded_accounts_data_size_limit` можна +використовувати для створення цієї інструкції. + +```rust +let instruction = ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(100_000); +``` + +### Обчислювальні одиниці + +Усі операції, виконані ончейн у рамках транзакції, вимагають різного обсягу +обчислювальних ресурсів, які витрачаються валідаторами під час обробки +(обчислювальна вартість). Найменшою одиницею виміру цих ресурсів є +_"обчислювальна одиниця"_. + +Під час обробки транзакції обчислювальні одиниці поступово споживаються кожною з +її інструкцій, виконуваних ончейн (вичерпуючи бюджет). Оскільки кожна інструкція +виконує різну логіку (запис у облікові записи, CPI, виконання системних викликів +тощо), кожна може споживати +[різну кількість](https://github.com/anza-xyz/agave/blob/b7bbe36918f23d98e2e73502e3c4cba78d395ba9/program-runtime/src/compute_budget.rs#L133-L178) +обчислювальних одиниць. + +> Програма може записувати деталі про використання своїх обчислювальних +> ресурсів, включаючи залишок у виділеному обчислювальному бюджеті. Більше +> інформації ви можете знайти в цьому посібнику з +> [оптимізації використання обчислювальних ресурсів](/content/guides/advanced/how-to-optimize-compute.md). + +Кожній транзакції виділяється +[ліміт обчислювальних одиниць](#compute-unit-limit), або за замовчуванням +встановлений часом виконання, або шляхом явного запиту на вищий ліміт. Якщо +транзакція перевищує свій ліміт обчислювальних одиниць, її обробка зупиняється, +що призводить до невдалої транзакції. + +Нижче наведено кілька поширених операцій, які мають обчислювальну вартість: + +- виконання інструкцій +- передача даних між програмами +- виконання системних викликів +- використання системних змінних (sysvars) +- логування за допомогою макросу `msg!` +- логування відкритих ключів +- створення програмних адрес (PDAs) +- міжпрограмні виклики (CPI) +- криптографічні операції + +> Для [міжпрограмних викликів](/docs/uk/core/cpi.md) викликана інструкція +> успадковує обчислювальний бюджет і ліміти свого батька. Якщо викликана +> інструкція споживає залишок бюджету транзакції або перевищує ліміт, весь +> ланцюжок викликів і обробка транзакції верхнього рівня зупиняються. + +Детальнішу інформацію про всі операції, які споживають обчислювальні одиниці, ви +можете знайти в +[ComputeBudget](https://github.com/anza-xyz/agave/blob/b7bbe36918f23d98e2e73502e3c4cba78d395ba9/program-runtime/src/compute_budget.rs#L19-L123) +в часі виконання Solana. + +### Ліміт обчислювальних одиниць + +Кожна транзакція має максимальну кількість обчислювальних одиниць (CU), які вона +може спожити, що називається _"лімітом обчислювальних одиниць"_. У часі +виконання Solana встановлено абсолютний максимальний ліміт +[1,4 мільйона CU](https://github.com/anza-xyz/agave/blob/b7bbe36918f23d98e2e73502e3c4cba78d395ba9/program-runtime/src/compute_budget_processor.rs#L19) +на транзакцію та за замовчуванням +[200 тисяч CU на інструкцію](https://github.com/anza-xyz/agave/blob/b7bbe36918f23d98e2e73502e3c4cba78d395ba9/program-runtime/src/compute_budget_processor.rs#L18). + +Транзакція може запитувати більш конкретний і оптимальний ліміт обчислювальних +одиниць, включивши одну інструкцію `SetComputeUnitLimit`. Це може бути як вищий, +так і нижчий ліміт. Але він ніколи не може перевищувати абсолютний максимальний +ліміт на транзакцію. + +Хоча ліміт обчислювальних одиниць за замовчуванням підходить для простих +транзакцій, він часто є менш оптимальним (як для часу виконання, так і для +користувача). Для складніших транзакцій, наприклад, виклику програм, що +виконують декілька CPI, може знадобитися запит вищого ліміту обчислювальних +одиниць для транзакції. + +Запит оптимальних лімітів обчислювальних одиниць для вашої транзакції є важливим +для зменшення витрат на транзакцію та кращого планування вашої транзакції в +мережі. Гаманці, dApps та інші сервіси повинні переконатися, що їхні запити на +обчислювальні одиниці є оптимальними, щоб забезпечити найкращий досвід для своїх +користувачів. + +> Для отримання додаткової інформації та найкращих практик прочитайте цей +> посібник про +> [запит оптимальних лімітів обчислювальних ресурсів](/content/guides/advanced/how-to-request-optimal-compute.md). + +### Ціна обчислювальної одиниці + +Якщо транзакція бажає сплатити вищу плату, щоб підвищити пріоритетність її +обробки, вона може встановити _"ціну обчислювальної одиниці"_. Ця ціна, у +поєднанні з [лімітом обчислювальних одиниць](#compute-unit-limit), буде +використовуватися для визначення плати за пріоритизацію транзакції. + +За замовчуванням +[ціна обчислювальної одиниці не встановлена](https://github.com/anza-xyz/agave/blob/b7bbe36918f23d98e2e73502e3c4cba78d395ba9/program-runtime/src/compute_budget_processor.rs#L38), +що призводить до відсутності додаткової плати за пріоритизацію. + +## Пріоритизаційні збори + +Як частина [Compute Budget](#compute-budget), час виконання підтримує +транзакції, що сплачують **опціональну** плату, відому як _"плата за +пріоритизацію"_. Сплата цієї додаткової плати допомагає підвищити пріоритетність +транзакції у порівнянні з іншими під час обробки, що призводить до швидшого +виконання. + +### Як розраховується плата за пріоритизацію + +Плата за пріоритизацію транзакції розраховується шляхом множення її **_ліміту +обчислювальних одиниць_** на **_ціну обчислювальної одиниці_** (вимірюється в +_мікролампортах_). Ці значення можна встановити один раз на транзакцію, +включивши такі інструкції Compute Budget: + +- [`SetComputeUnitLimit`](https://github.com/anza-xyz/agave/blob/b7bbe36918f23d98e2e73502e3c4cba78d395ba9/sdk/src/compute_budget.rs#L47-L50) + — встановлення максимальної кількості обчислювальних одиниць, які може спожити + транзакція. +- [`SetComputeUnitPrice`](https://github.com/anza-xyz/agave/blob/b7bbe36918f23d98e2e73502e3c4cba78d395ba9/sdk/src/compute_budget.rs#L52-L55) + — встановлення бажаної додаткової плати, яку транзакція готова сплатити для + підвищення пріоритетності. + +Якщо інструкція `SetComputeUnitLimit` не надана, буде використовуватися +[ліміт обчислювальних одиниць за замовчуванням](#compute-unit-limit). + +Якщо інструкція `SetComputeUnitPrice` не надана, транзакція за замовчуванням +матиме найнижчий пріоритет (тобто відсутність пріоритизаційної плати). + +### Як встановити плату за пріоритизацію + +Плата за пріоритизацію транзакції встановлюється шляхом включення інструкції +`SetComputeUnitPrice` та, за бажанням, інструкції `SetComputeUnitLimit`. Час +виконання використовуватиме ці значення для розрахунку плати за пріоритизацію, +яка буде використовуватися для пріоритизації даної транзакції у блоці. + +Ви можете створити кожну з цих інструкцій за допомогою функцій Rust або +`@solana/web3.js`. Потім кожну інструкцію можна включити в транзакцію та +надіслати до кластера як звичайно. Дивіться також +[найкращі практики](#prioritization-fee-best-practices) нижче. + +На відміну від інших інструкцій усередині транзакції Solana, інструкції Compute +Budget **НЕ** вимагають жодних облікових записів. Транзакція з кількома +інструкціями одного типу завершиться невдачею. + + + +Транзакції можуть містити лише **одну інструкцію кожного типу** інструкцій +обчислювального бюджету. Дублікати інструкцій призведуть до помилки +[`TransactionError::DuplicateInstruction`](https://github.com/anza-xyz/agave/blob/b7bbe36918f23d98e2e73502e3c4cba78d395ba9/sdk/src/transaction/error.rs#L143-L145) +і, зрештою, до невдачі транзакції. + + + +#### Rust + +Бібліотека `solana-sdk` включає функції в рамках +[`ComputeBudgetInstruction`](https://docs.rs/solana-sdk/latest/solana_sdk/compute_budget/enum.ComputeBudgetInstruction.html) +для створення інструкцій для встановлення _ліміту обчислювальних одиниць_ та +_ціни обчислювальної одиниці_. + +```rust +let instruction = ComputeBudgetInstruction::set_compute_unit_limit(300_000); +``` + +```rust +let instruction = ComputeBudgetInstruction::set_compute_unit_price(1); +``` + +#### Javascript + +Бібліотека `@solana/web3.js` включає функції в класі +[`ComputeBudgetProgram`](https://solana-labs.github.io/solana-web3.js/v1.x/classes/ComputeBudgetProgram.html) +для створення інструкцій для встановлення _ліміту обчислювальних одиниць_ та +_ціни обчислювальної одиниці_. + +```js +const instruction = ComputeBudgetProgram.setComputeUnitLimit({ + units: 300_000, +}); +``` + +```js +const instruction = ComputeBudgetProgram.setComputeUnitPrice({ + microLamports: 1, +}); +``` + +### Найкращі практики для плати за пріоритизацію + +Нижче наведено загальну інформацію про найкращі практики для пріоритизаційних +зборів. Більш детальну інформацію можна знайти в цьому посібнику про +[запит оптимального використання обчислювальних ресурсів](/content/guides/advanced/how-to-request-optimal-compute.md), +включаючи симуляцію транзакції для визначення її приблизного використання +обчислювальних ресурсів. + +#### Запитуйте мінімальну кількість обчислювальних одиниць + +Транзакції повинні запитувати мінімальну кількість обчислювальних одиниць, +необхідну для виконання, щоб мінімізувати збори. Також зауважте, що збори не +коригуються, якщо кількість запитаних обчислювальних одиниць перевищує фактично +спожиту кількість у виконаній транзакції. + +#### Отримуйте останні пріоритизаційні збори + +Перед надсиланням транзакції до кластеру ви можете скористатися методом RPC +[`getRecentPrioritizationFees`](/docs/uk/rpc/http/getRecentPrioritizationFees.mdx), +щоб отримати список останніх сплачених пріоритизаційних зборів у нещодавно +оброблених блоках вузла. + +Ви можете використовувати ці дані для оцінки відповідної плати за пріоритизацію +для вашої транзакції, щоб: + +(a) підвищити ймовірність її обробки кластером та (b) мінімізувати сплачені +збори. + +## Оренда + +Плата, що депонується на кожен +[Обліковий запис Solana](/docs/uk/core/accounts.md) для збереження його +пов'язаних даних в ончейні, називається "_орендою_". Ця плата утримується у +звичайному балансі лампортів на кожному обліковому записі та може бути повернута +під час закриття облікового запису. + +> Оренда відрізняється від [транзакційних зборів](#transaction-fees). Оренда +> "сплачується" (утримується в Обліковому записі) для збереження даних на +> блокчейні Solana та може бути повернута. У той час як транзакційні збори +> сплачуються за обробку +> [інструкцій](/docs/uk/core/transactions.md#instructions) у мережі. + +Усі облікові записи повинні підтримувати достатньо високий баланс лампортів +(відносно їх виділеного простору), щоб стати +[звільненими від оренди](#rent-exempt) і залишатися на блокчейні Solana. +Будь-яка транзакція, що намагається зменшити баланс облікового запису нижче його +відповідного мінімального балансу для звільнення від оренди, завершиться +невдачею (якщо тільки баланс не зменшується до нуля). + +Коли власник облікового запису більше не бажає зберігати ці дані в ончейні та +доступними в глобальному стані, він може закрити обліковий запис і повернути +орендний депозит. + +Це здійснюється шляхом виведення (переказу) усього балансу лампортів облікового +запису на інший обліковий запис (наприклад, ваш гаманець). Зменшивши баланс +облікового запису до рівно `0`, час виконання видалить обліковий запис і його +пов'язані дані з мережі в процесі _"[збирання сміття](#garbage-collection)"_. + +### Ставка оренди + +Ставка оренди Solana встановлюється на рівні всієї мережі, головним чином +базуючись на часі виконання +"[лампорти _за_ байт _за_ рік](https://github.com/anza-xyz/agave/blob/b7bbe36918f23d98e2e73502e3c4cba78d395ba9/sdk/program/src/rent.rs#L27-L34)". +Наразі ставка оренди є статичною величиною та зберігається в +[системній змінній Rent](https://docs.anza.xyz/runtime/sysvars#rent). + +Ця ставка оренди використовується для розрахунку точної суми оренди, яка повинна +бути утримана в обліковому записі для виділеного простору облікового запису +(тобто кількість даних, які можуть бути збережені в обліковому записі). Чим +більше простору виділяє обліковий запис, тим вищим буде утриманий орендний +депозит. + +### Звільнення від оренди + +Облікові записи повинні підтримувати баланс лампортів, що перевищує мінімум, +необхідний для зберігання відповідних даних в ончейні. Це називається +"_звільненням від оренди_", а цей баланс називається "_мінімальним балансом для +звільнення від оренди_". + +> Нові облікові записи (та програми) на Solana **ЗОБОВ'ЯЗАНІ** бути +> ініціалізовані з достатньою кількістю лампортів, щоб стати _звільненими від +> оренди_. Так було не завжди. Раніше час виконання періодично та автоматично +> стягував плату з кожного облікового запису, що мав баланс нижче мінімуму для +> звільнення від оренди. Зрештою, такі облікові записи знижувалися до нульового +> балансу та видалялися з глобального стану (якщо їх не поповнювали вручну). + +У процесі створення нового облікового запису необхідно переконатися, що ви +депонуєте достатньо лампортів, щоб перевищити цей мінімальний баланс. Все, що +нижче цього мінімального порогу, призведе до невдачі транзакції. + +Кожного разу, коли баланс облікового запису зменшується, час виконання +перевіряє, чи залишиться баланс цього облікового запису вище мінімального +балансу для звільнення від оренди. Якщо тільки баланс не знижується до рівно `0` +(закриття облікового запису), транзакції, які спричиняють падіння балансу +облікового запису нижче порогу звільнення від оренди, завершаться невдачею. + +Специфічний мінімальний баланс для облікового запису, щоб стати звільненим від +оренди, залежить від поточної [ставки оренди](#rent-rate) блокчейну та бажаного +обсягу простору, який обліковий запис хоче виділити (розмір облікового запису). +Тому рекомендується використовувати RPC-метод +[`getMinimumBalanceForRentExemption`](/docs/uk/rpc/http/getMinimumBalanceForRentExemption.mdx) +для розрахунку конкретного балансу для заданого розміру облікового запису. + +Суму необхідного орендного депозиту також можна оцінити за допомогою підкоманди +CLI [`solana rent`](https://docs.anza.xyz/cli/usage#solana-rent). + +```shell +solana rent 15000 + +# output +Rent per byte-year: 0.00000348 SOL +Rent per epoch: 0.000288276 SOL +Rent-exempt minimum: 0.10529088 SOL +``` + +### Збирання сміття + +Облікові записи, які не підтримують баланс лампортів більше нуля, видаляються з +мережі в процесі, відомому як _збирання сміття_. Цей процес виконується, щоб +зменшити загальну кількість збережених у мережі даних, які більше не +використовуються або не підтримуються. + +Після успішного зменшення балансу облікового запису до рівно `0` транзакцією, +збирання сміття виконується автоматично часом виконання. Будь-яка транзакція, +яка намагається зменшити баланс облікового запису нижче його мінімального +балансу для звільнення від оренди (що не дорівнює нулю), завершиться невдачею. + + +Важливо зазначити, що збирання сміття відбувається **після** завершення виконання транзакції. Якщо є інструкція "закрити" обліковий запис, зменшивши баланс облікового запису до нуля, обліковий запис може бути "повторно відкритий" у тій самій транзакції за допомогою наступної інструкції. Якщо стан облікового запису не було очищено в інструкції "закрити", наступна інструкція "повторного відкриття" матиме той самий стан облікового запису. Це є проблемою безпеки, тому важливо знати точний момент, коли збирання сміття набирає чинності. + + +Навіть після того, як обліковий запис було видалено з мережі (через збирання +сміття), він все ще може мати транзакції, пов'язані з його адресою (або в +історії, або в майбутньому). Незважаючи на те, що блокчейн-експлорер Solana може +відображати повідомлення типу "обліковий запис не знайдено", ви все одно можете +переглядати історію транзакцій, пов'язаних із цим обліковим записом. + +Ви можете прочитати +[запропоновану реалізацію](https://docs.anza.xyz/implemented-proposals/persistent-account-storage#garbage-collection) +для збирання сміття, щоб дізнатися більше. diff --git a/docs/locales/uk/core/index.md b/docs/locales/uk/core/index.md new file mode 100644 index 000000000..8743b8699 --- /dev/null +++ b/docs/locales/uk/core/index.md @@ -0,0 +1,117 @@ +--- +title: Основні концепції +sidebarSortOrder: 2 +description: + Дізнайтеся про основні концепції блокчейну Solana, включаючи облікові записи, + транзакції, програми, адреси, отримані від програм, міжпрограмні виклики та як + працюють токени на Solana. +--- + +Розвивайте глибоке розуміння основних концепцій, які роблять Solana унікальним +серед інших блокчейнів. Розуміння "моделі програмування Solana" через ці ключові +концепції дуже важливе для максимального успіху як розробника блокчейну Solana. + +## Модель облікових записів Solana + +У Solana всі дані зберігаються в тому, що називається "обліковими записами". +Організація даних у блокчейні Solana нагадує +[сховище ключів і значень](https://uk.wikipedia.org/wiki/Key%E2%80%93value_%D0%B1%D0%B0%D0%B7%D0%B0_%D0%B4%D0%B0%D0%BD%D0%B8%D1%85), +де кожен запис у базі даних називається "обліковим записом". + +Дізнайтеся більше про [Облікові записи](/docs/core/accounts.md) тут. + +## Транзакції та інструкції + +У Solana ми надсилаємо [транзакції](/docs/core/transactions#transaction), щоб +взаємодіяти з мережею. Транзакції включають одну або більше +[інструкцій](/docs/core/transactions#instruction), кожна з яких представляє +конкретну операцію для обробки. Логіка виконання інструкцій зберігається в +[програмах](/docs/core/programs), розгорнутих у мережі Solana, де кожна програма +має свій власний набір інструкцій. + +Дізнайтеся більше про [Транзакції](/docs/core/transactions.md) та +[Інструкції](/docs/core/transactions.md#instruction) тут. + +## Плата на Solana + +Блокчейн Solana має кілька типів зборів та витрат, які виникають при +використанні мережі без дозволу. Вони поділяються на кілька основних типів: + +- [Транзакційні збори](/docs/core/fees.md#transaction-fees) — плата за обробку + транзакцій/інструкцій валідаторами. +- [Пріоритизаційні збори](/docs/core/fees.md#prioritization-fees) — опціональна + плата для підвищення порядку обробки транзакцій. +- [Оренда](/docs/core/fees.md#rent) — утримуваний баланс для збереження даних в + ончейні. + +Дізнайтеся більше про [Плату на Solana](/docs/core/fees.md) тут. + +## Програми на Solana + +У екосистемі Solana "смарт-контракти" називаються програмами. Кожна програма є +ончейн-обліковим записом, що зберігає виконувану логіку, організовану у функції, +що називаються _інструкціями_, і викликаються через функції обробників +інструкцій у відповідній розгорнутій програмі. + +Дізнайтеся більше про [Програми на Solana](/docs/core/programs.md) тут. + +## Адреси, отримані від програм + +Адреси, отримані від програм (Program Derived Addresses, PDAs), надають +розробникам Solana дві основні можливості: + +- **Детерміновані адреси облікових записів**: PDAs забезпечують механізм + детермінованого отримання адреси за допомогою комбінації опціональних + "насіння" (заданих вхідних даних) і конкретного ідентифікатора програми. +- **Дозволити підписання програмою**: Час виконання Solana дозволяє програмам + "підписувати" PDAs, які отримані від їх ідентифікатора програми. + +Можна уявити PDAs як спосіб створення ончейн-структур, схожих на хеш-таблиці, з +набору заданих вхідних даних (наприклад, рядків, чисел та інших адрес облікових +записів). + +Дізнайтеся більше про [Адреси, отримані від програм](/docs/core/pda.md) тут. + +## Міжпрограмні виклики + +Міжпрограмний виклик (Cross Program Invocation, CPI) означає, що одна програма +викликає інструкції іншої програми. Цей механізм дозволяє програмам Solana бути +композитивними. + +Можна уявити інструкції як API-ендпоінти, які програма надає мережі, а CPI як +один API, що викликає інший API внутрішньо. + +Дізнайтеся більше про [Міжпрограмні виклики](/docs/core/cpi.md) тут. + +## Токени на Solana + +Токени — це цифрові активи, які представляють право власності на різні категорії +активів. Токенізація дозволяє оцифровувати права власності, виступаючи +фундаментальним компонентом для управління як взаємозамінними, так і +невзаємозамінними активами. + +- Взаємозамінні токени представляють взаємозамінні та подільні активи одного + типу і вартості (наприклад, USDC). +- Невзаємозамінні токени (NFT) представляють право власності на неподільні + активи (наприклад, твори мистецтва). + +Дізнайтеся більше про [Токени на Solana](/docs/core/tokens.md) тут. + +## Кластери та кінцеві точки + +Блокчейн Solana має кілька різних груп валідаторів, відомих як +[Кластери](/docs/core/clusters.md). Кожна з них виконує різні завдання в +екосистемі та має спеціалізовані вузли API для виконання запитів +[JSON-RPC](/docs/rpc/index.mdx) для свого кластеру. + +Індивідуальні вузли в кластері належать і управляються третіми сторонами, +причому для кожного з них доступна публічна кінцева точка. + +Є три основні кластери в мережі Solana, кожен з яких має свою публічну кінцеву +точку: + +- Mainnet - `https://api.mainnet-beta.solana.com` +- Devnet - `https://api.devnet.solana.com` +- Testnet - `https://api.testnet.solana.com` + +Дізнайтеся більше про [Кластери та кінцеві точки](/docs/core/clusters.md) тут. diff --git a/docs/locales/uk/core/pda.md b/docs/locales/uk/core/pda.md new file mode 100644 index 000000000..b3451e66e --- /dev/null +++ b/docs/locales/uk/core/pda.md @@ -0,0 +1,403 @@ +--- +title: Програмно Виведені Адреси (PDA) +sidebarLabel: Програмно Виведені Адреси +sidebarSortOrder: 5 +description: + Дізнайтеся про Програмно Виведені Адреси (PDA) в Solana — детерміновані адреси + облікових записів, які забезпечують безпечне підписання програмами. + Розберіться у виведенні PDA, канонічних бампах і створенні облікових записів + PDA. +--- + +Програмно Виведені Адреси (PDA) надають розробникам у Solana два основних +варіанти використання: + +- **Детерміновані адреси облікових записів**: PDA надають механізм для + детермінованого виведення адреси за допомогою комбінації необов’язкових + "сідів" (заздалегідь визначених вхідних даних) та певного ідентифікатора + програми. +- **Забезпечення підписання програмами**: Рантайм Solana дозволяє програмам + "підписуватися" від імені PDA, які виведені з їхнього ідентифікатора програми. + +Можна уявити PDA як спосіб створення структур, схожих на хешмапи, у блокчейні з +використанням заздалегідь визначених вхідних даних (наприклад, рядків, чисел і +інших адрес облікових записів). + +Перевага цього підходу полягає в тому, що він усуває потребу в точному +відстеженні адреси. Натомість вам потрібно лише згадати конкретні вхідні дані, +які використовувались для її виведення. + +![Програмно Виведена Адреса](/assets/docs/core/pda/pda.svg) + +Важливо розуміти, що просте виведення Програмно Виведеної Адреси (PDA) не +автоматично створює обліковий запис у блокчейні за цією адресою. Облікові записи +з PDA як адресою в блокчейні повинні бути явно створені через програму, яка +використовувалась для виведення адреси. Можна уявити виведення PDA як пошук +адреси на карті. Мати адресу — це ще не означає, що за цією адресою щось +побудовано. + +> У цьому розділі буде розглянуто деталі виведення PDA. Деталі того, як програми +> використовують PDA для підписання, будуть розглянуті в розділі +> [Взаємодія між програмами (CPI)](/docs/uk/core/cpi.md), оскільки це потребує +> контексту для обох концепцій. + +## Основні моменти + +- PDA — це адреси, які виводяться детерміновано з використанням комбінації + визначених користувачем сідів, бамп сіда та ідентифікатора програми. + +- PDA — це адреси, які виходять за межі кривої Ed25519 і не мають відповідного + приватного ключа. + +- Програми Solana можуть програмно "підписуватися" від імені PDA, які виведені + за допомогою їхнього ідентифікатора програми. + +- Виведення PDA не створює автоматично обліковий запис у блокчейні. + +- Обліковий запис з PDA як адресою повинен бути явно створений через спеціальну + інструкцію в програмі Solana. + +## Що таке PDA + +PDA — це адреси, які виводяться детерміновано та виглядають як стандартні +публічні ключі, але не мають асоційованих приватних ключів. Це означає, що жоден +зовнішній користувач не може згенерувати дійсний підпис для цієї адреси. Однак, +рантайм Solana дозволяє програмам програмно "підписуватися" від імені PDA без +необхідності у приватному ключі. + +Для контексту, +[Keypairs](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/sdk/src/signer/keypair.rs#L25) +у Solana є точками на кривій Ed25519 (еліптична криптографія), які мають +публічний ключ і відповідний приватний ключ. Ми часто використовуємо публічні +ключі як унікальні ідентифікатори для нових облікових записів у блокчейні, а +приватні ключі для підписання. + +![Адреса на кривій](/assets/docs/core/pda/address-on-curve.svg) + +PDA — це точка, яка навмисно виводиться за межі кривої Ed25519 з використанням +заздалегідь визначених вхідних даних. Точка, яка не знаходиться на кривій +Ed25519, не має дійсного відповідного приватного ключа і не може бути +використана для криптографічних операцій (підписання). + +PDA може бути використана як адреса (унікальний ідентифікатор) для облікового +запису в блокчейні, забезпечуючи спосіб зручного зберігання, мапування та +отримання стану програми. + +![Адреса поза кривою](/assets/docs/core/pda/address-off-curve.svg) + +## Як вивести PDA + +Виведення PDA вимагає 3 вхідних даних. + +- **Необов’язкові сіди**: Заздалегідь визначені вхідні дані (наприклад, рядок, + число, інші адреси облікових записів), які використовуються для виведення PDA. + Ці вхідні дані конвертуються в буфер байтів. +- **Бамп сід**: Додатковий вхідний параметр (зі значенням між 255-0), який + використовується для забезпечення того, що згенерований PDA знаходиться поза + кривою Ed25519. Цей бамп сід (починаючи з 255) додається до необов’язкових + сідів під час генерації PDA, щоб "виштовхнути" точку за межі кривої Ed25519. + Бамп сід іноді називають "нонсом". +- **Ідентифікатор програми**: Адреса програми, з якої виведений PDA. Ця ж + програма може "підписуватися" від імені PDA. + +![Виведення PDA](/assets/docs/core/pda/pda-derivation.svg) + +Приклади нижче включають посилання на Solana Playground, де ви можете запустити +приклади в редакторі прямо у веббраузері. + +### FindProgramAddress + +Щоб вивести PDA, ми можемо використовувати метод +[`findProgramAddressSync`](https://github.com/solana-labs/solana-web3.js/blob/ca9da583a39cdf8fd874a2e03fccdc849e29de34/packages/library-legacy/src/publickey.ts#L212) +з пакета [`@solana/web3.js`](https://www.npmjs.com/package/@solana/web3.js). +Існують еквіваленти цієї функції на інших мовах програмування (наприклад, +[Rust](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/sdk/program/src/pubkey.rs#L484)), +але в цьому розділі ми розглянемо приклади з використанням Javascript. + +Під час використання методу `findProgramAddressSync` ми передаємо: + +- заздалегідь визначені необов’язкові сіди, перетворені в буфер байтів, та +- ідентифікатор програми (адресу), використаний для виведення PDA. + +Після знаходження дійсного PDA, `findProgramAddressSync` повертає як адресу +(PDA), так і бамп сід, який використовувався для виведення PDA. + +Нижче наведено приклад виведення PDA без надання необов’язкових сідів. + +```ts /[]/ +import { PublicKey } from "@solana/web3.js"; + +const programId = new PublicKey("11111111111111111111111111111111"); + +const [PDA, bump] = PublicKey.findProgramAddressSync([], programId); + +console.log(`PDA: ${PDA}`); +console.log(`Bump: ${bump}`); +``` + +Ви можете запустити цей приклад на +[Solana Playground](https://beta.solpg.io/66031e5acffcf4b13384cfef). Виведення +PDA та бамп сіда завжди буде однаковим: + +``` +PDA: Cu7NwqCXSmsR5vgGA3Vw9uYVViPi3kQvkbKByVQ8nPY9 +Bump: 255 +``` + +У наступному прикладі додається необов’язковий сід "helloWorld". + +```ts /string/ +import { PublicKey } from "@solana/web3.js"; + +const programId = new PublicKey("11111111111111111111111111111111"); +const string = "helloWorld"; + +const [PDA, bump] = PublicKey.findProgramAddressSync( + [Buffer.from(string)], + programId, +); + +console.log(`PDA: ${PDA}`); +console.log(`Bump: ${bump}`); +``` + +Ви також можете запустити цей приклад на +[Solana Playground](https://beta.solpg.io/66031ee5cffcf4b13384cff0). Виведення +PDA та бамп сіда завжди буде однаковим: + +``` +PDA: 46GZzzetjCURsdFPb7rcnspbEMnCBXe9kpjrsZAkKb6X +Bump: 254 +``` + +Зверніть увагу, що бамп сід дорівнює 254. Це означає, що 255 вивів точку на +кривій Ed25519 і не є дійсним PDA. + +Бамп сід, який повертається функцією `findProgramAddressSync`, — це перше +значення (у діапазоні від 255 до 0) для заданої комбінації необов’язкових сідів +та ідентифікатора програми, яке виводить дійсний PDA. + +> Це перше дійсне значення бамп сіда називається "канонічним бампом". З метою +> безпеки програм рекомендовано використовувати лише канонічний бамп при роботі +> з PDA. + +### CreateProgramAddress + +У своїй основі, `findProgramAddressSync` ітеративно додає додатковий бамп сід +(нонс) до буфера сідів і викликає метод +[`createProgramAddressSync`](https://github.com/solana-labs/solana-web3.js/blob/ca9da583a39cdf8fd874a2e03fccdc849e29de34/packages/library-legacy/src/publickey.ts#L168). +Значення бамп сіда починається з 255 і зменшується на 1, доки не буде знайдено +дійсний PDA (поза кривою). + +Ви можете відтворити попередній приклад, використовуючи +`createProgramAddressSync` та явно передавши бамп сід зі значенням 254. + +```ts /bump/ +import { PublicKey } from "@solana/web3.js"; + +const programId = new PublicKey("11111111111111111111111111111111"); +const string = "helloWorld"; +const bump = 254; + +const PDA = PublicKey.createProgramAddressSync( + [Buffer.from(string), Buffer.from([bump])], + programId, +); + +console.log(`PDA: ${PDA}`); +``` + +Запустіть цей приклад вище на +[Solana Playground](https://beta.solpg.io/66031f8ecffcf4b13384cff1). За +однакових сідів та ідентифікатора програми, виведення PDA буде відповідати +попередньому прикладу: + +``` +PDA: 46GZzzetjCURsdFPb7rcnspbEMnCBXe9kpjrsZAkKb6X +``` + +### Канонічний бамп + +"Канонічний бамп" відноситься до першого значення бамп сіда (починаючи з 255 і +зменшуючи на 1), яке виводить дійсний PDA. З метою безпеки програм рекомендовано +використовувати лише PDA, виведені з канонічного бампа. + +Використовуючи попередній приклад як орієнтир, приклад нижче намагається вивести +PDA, використовуючи всі значення бамп сіда від 255 до 0. + +```ts +import { PublicKey } from "@solana/web3.js"; + +const programId = new PublicKey("11111111111111111111111111111111"); +const string = "helloWorld"; + +// Loop through all bump seeds for demonstration +for (let bump = 255; bump >= 0; bump--) { + try { + const PDA = PublicKey.createProgramAddressSync( + [Buffer.from(string), Buffer.from([bump])], + programId, + ); + console.log("bump " + bump + ": " + PDA); + } catch (error) { + console.log("bump " + bump + ": " + error); + } +} +``` + +Запустіть приклад на +[Solana Playground](https://beta.solpg.io/66032009cffcf4b13384cff2), і ви +повинні побачити наступний результат: + +``` +bump 255: Error: Invalid seeds, address must fall off the curve +bump 254: 46GZzzetjCURsdFPb7rcnspbEMnCBXe9kpjrsZAkKb6X +bump 253: GBNWBGxKmdcd7JrMnBdZke9Fumj9sir4rpbruwEGmR4y +bump 252: THfBMgduMonjaNsCisKa7Qz2cBoG1VCUYHyso7UXYHH +bump 251: EuRrNqJAofo7y3Jy6MGvF7eZAYegqYTwH2dnLCwDDGdP +bump 250: Error: Invalid seeds, address must fall off the curve +... +// remaining bump outputs +``` + +Як і очікувалось, бамп сід 255 викликає помилку, а перший бамп сід, який +виводить дійсний PDA, дорівнює 254. + +Однак зверніть увагу, що бамп сіди 253-251 також виводять дійсні PDA з різними +адресами. Це означає, що для заданих необов’язкових сідів та `programId` бамп +сід з іншим значенням все ще може вивести дійсний PDA. + + + При створенні програм на Solana рекомендовано додавати перевірки безпеки, + які підтверджують, що PDA, переданий до програми, виведений з використанням + канонічного бампа. Невиконання цього може призвести до вразливостей, які + дозволять несподіваним обліковим записам передаватися до програми. + + +## Створення облікових записів PDA + +Ця програмна демонстрація на +[Solana Playground](https://beta.solpg.io/github.com/ZYJLiu/doc-examples/tree/main/pda-account) +показує, як створити обліковий запис, використовуючи PDA як адресу нового +облікового запису. Програма написана з використанням фреймворку Anchor. + +У файлі `lib.rs` ви знайдете наступну програму, яка включає єдину інструкцію для +створення нового облікового запису з використанням PDA як адреси облікового +запису. Новий обліковий запис зберігає адресу `user` та `bump` сід, який +використовувався для виведення PDA. + +```rust filename="lib.rs" {11-14,26-29} +use anchor_lang::prelude::*; + +declare_id!("75GJVCJNhaukaa2vCCqhreY31gaphv7XTScBChmr1ueR"); + +#[program] +pub mod pda_account { + use super::*; + + pub fn initialize(ctx: Context) -> Result<()> { + let account_data = &mut ctx.accounts.pda_account; + // store the address of the `user` + account_data.user = *ctx.accounts.user.key; + // store the canonical bump + account_data.bump = ctx.bumps.pda_account; + Ok(()) + } +} + +#[derive(Accounts)] +pub struct Initialize<'info> { + #[account(mut)] + pub user: Signer<'info>, + + #[account( + init, + // set the seeds to derive the PDA + seeds = [b"data", user.key().as_ref()], + // use the canonical bump + bump, + payer = user, + space = 8 + DataAccount::INIT_SPACE + )] + pub pda_account: Account<'info, DataAccount>, + pub system_program: Program<'info, System>, +} + +#[account] + +#[derive(InitSpace)] +pub struct DataAccount { + pub user: Pubkey, + pub bump: u8, +} +``` + +Сіди, які використовуються для виведення PDA, включають зафіксований рядок +`data` та адресу облікового запису `user`, передану в інструкції. Фреймворк +Anchor автоматично виводить канонічний `bump` сід. + +```rust /data/ /user.key()/ /bump/ +#[account( + init, + seeds = [b"data", user.key().as_ref()], + bump, + payer = user, + space = 8 + DataAccount::INIT_SPACE +)] +pub pda_account: Account<'info, DataAccount>, +``` + +Обмеження `init` вказує Anchor викликати Системну Програму для створення нового +облікового запису з використанням PDA як адреси. Це виконується за допомогою +[Взаємодії між програмами (CPI)](/docs/uk/core/cpi.md). + +```rust /init/ +#[account( + init, + seeds = [b"data", user.key().as_ref()], + bump, + payer = user, + space = 8 + DataAccount::INIT_SPACE +)] +pub pda_account: Account<'info, DataAccount>, +``` + +У тестовому файлі (`pda-account.test.ts`), розташованому за посиланням на Solana +Playground, наданим вище, ви знайдете еквівалентний код на Javascript для +виведення PDA. + +```ts /data/ /user.publicKey/ +const [PDA] = PublicKey.findProgramAddressSync( + [Buffer.from("data"), user.publicKey.toBuffer()], + program.programId, +); +``` + +Далі надсилається транзакція для виклику інструкції `initialize`, щоб створити +новий обліковий запис у блокчейні з використанням PDA як адреси. Після +надсилання транзакції PDA використовується для отримання облікового запису в +блокчейні, який був створений за цією адресою. + +```ts /initialize()/ /PDA/ {14} +it("Is initialized!", async () => { + const transactionSignature = await program.methods + .initialize() + .accounts({ + user: user.publicKey, + pdaAccount: PDA, + }) + .rpc(); + + console.log("Transaction Signature:", transactionSignature); +}); + +it("Fetch Account", async () => { + const pdaAccount = await program.account.dataAccount.fetch(PDA); + console.log(JSON.stringify(pdaAccount, null, 2)); +}); +``` + +Зверніть увагу, що якщо ви викликаєте інструкцію `initialize` більше одного +разу, використовуючи ту саму адресу `user` як сід, транзакція завершиться +помилкою. Це відбувається тому, що обліковий запис вже існує за виведеною +адресою. diff --git a/docs/locales/uk/core/programs.md b/docs/locales/uk/core/programs.md new file mode 100644 index 000000000..0c796f12f --- /dev/null +++ b/docs/locales/uk/core/programs.md @@ -0,0 +1,96 @@ +--- +title: Програми +sidebarLabel: Програми на Solana +sidebarSortOrder: 4 +description: + Дізнайтеся про програми Solana (смарт-контракти) та як розробляти їх за + допомогою Rust або фреймворку Anchor. Зрозумійте процес розгортання, оновлення + та перевірки програм у мережі Solana. +--- + +У екосистемі Solana "смарт-контракти" називаються програмами. Кожна +[програма](/docs/uk/core/accounts.md#program-account) є обліковим записом у +блокчейні, який зберігає виконувану логіку, організовану у вигляді конкретних +функцій, які називаються +[інструкціями](/docs/uk/core/transactions.md#instruction). + +## Основні моменти + +- Програми — це облікові записи у блокчейні, які містять виконуваний код. Цей + код організований у вигляді окремих функцій, відомих як інструкції. + +- Програми не зберігають стану, але можуть включати інструкції для створення + нових облікових записів, які використовуються для зберігання та управління + станом програми. + +- Програми можуть оновлюватися за допомогою "авторитету оновлення". Програма + стає незмінною, коли авторитет оновлення встановлюється у значення null. + +- Перевірювані збірки дозволяють користувачам переконатися, що програми у + блокчейні відповідають доступному публічно вихідному коду. + +## Написання програм Solana + +Програми Solana зазвичай пишуться мовою програмування +[Rust](https://doc.rust-lang.org/book/) з використанням двох підходів: + +- [Anchor](/docs/uk/programs/anchor): Фреймворк, створений для розробки програм + Solana. Він забезпечує швидший і простіший спосіб написання програм, + використовуючи макроси Rust для значного зменшення обсягу шаблонного коду. Для + початківців рекомендується починати з фреймворку Anchor. + +- [Нативний Rust](/content/guides/getstarted/intro-to-native-rust.md): Цей + підхід передбачає написання програм Solana на Rust без використання + фреймворків. Він надає більше гнучкості, але супроводжується підвищеною + складністю. + +## Оновлення програм Solana + +Програми у блокчейні можуть бути +[безпосередньо змінені](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/programs/bpf_loader/src/lib.rs#L675) +обліковим записом, призначеним як "авторитет оновлення", зазвичай це обліковий +запис, який початково розгорнув програму. + +Якщо +[авторитет оновлення](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/programs/bpf_loader/src/lib.rs#L865) +скасований і встановлений у `None`, програма стає незмінною і більше не може +бути оновлена. + +## Перевірювані програми + +Забезпечення цілісності та перевірюваності коду у блокчейні є важливим. +Перевірювана збірка гарантує, що виконуваний код, розгорнутий у блокчейні, може +бути незалежно перевірений на відповідність його публічному вихідному коду +будь-якою третьою стороною. Цей процес підвищує прозорість і довіру, дозволяючи +виявляти розбіжності між вихідним кодом і розгорнутою програмою. + +Спільнота розробників Solana створила інструменти для підтримки перевірюваних +збірок, які дозволяють як розробникам, так і користувачам переконатися, що +програми у блокчейні точно відображають їхній публічний вихідний код. + +- **Пошук перевірених програм**: Для швидкої перевірки програм користувачі + можуть знайти адресу програми у [SolanaFM](https://solana.fm/) Explorer і + перейти на вкладку "Verification". Приклад перевіреної програми можна побачити + [тут](https://solana.fm/address/PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY). + +- **Інструменти перевірки**: CLI + [Solana Verifiable Build](https://github.com/Ellipsis-Labs/solana-verifiable-build) + від Ellipsis Labs дозволяє незалежно перевірити програми у блокчейні на + відповідність опублікованому вихідному коду. + +- **Підтримка перевірюваних збірок в Anchor**: Anchor має вбудовану підтримку + перевірюваних збірок. Деталі можна знайти у + [документації Anchor](https://www.anchor-lang.com/docs/verifiable-builds). + +## Berkeley Packet Filter (BPF) + +Solana використовує [інфраструктуру компілятора LLVM](https://llvm.org/) для +компіляції програм у файли формату +[Executable and Linkable Format (ELF)](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format). +Ці файли включають модифіковану версію байт-коду +[Berkeley Packet Filter (eBPF)](https://en.wikipedia.org/wiki/EBPF) для програм +Solana, відомого як "Solana Bytecode Format" (sBPF). + +Використання LLVM дозволяє Solana підтримувати будь-яку мову програмування, яка +може компілюватися у BPF-бекенд LLVM. Це значно підвищує гнучкість Solana як +платформи для розробки. diff --git a/docs/locales/uk/core/tokens.md b/docs/locales/uk/core/tokens.md new file mode 100644 index 000000000..c9cd3812a --- /dev/null +++ b/docs/locales/uk/core/tokens.md @@ -0,0 +1,597 @@ +--- +title: "Токени на Solana" +sidebarSortOrder: 7 +description: + Дізнайтеся про токени Solana (SPL Tokens), включаючи взаємозамінні та + невзаємозамінні токени, Програму Токенів, Програму Розширень Токенів, облікові + записи випуску токенів, токен-облікові записи, а також практичні приклади + створення і управління токенами на Solana. +--- + +Токени — це цифрові активи, які представляють право власності на різні категорії +активів. Токенізація дозволяє цифровізувати права власності, виступаючи як +фундаментальний компонент для управління взаємозамінними та невзаємозамінними +активами. + +- **Взаємозамінні токени** представляють активи, які можна замінювати і ділити + (наприклад, USDC). +- **Невзаємозамінні токени (NFT)** представляють право власності на неподільні + активи (наприклад, витвори мистецтва). + +У цьому розділі буде розглянуто основи представлення токенів у Solana. Ці токени +називаються SPL +([Solana Program Library](https://github.com/solana-labs/solana-program-library)). + +- [Програма Токенів](#token-program) містить всю логіку інструкцій для взаємодії + з токенами в мережі (як взаємозамінними, так і невзаємозамінними). + +- [Обліковий запис випуску токенів](#mint-account) представляє певний тип токена + і зберігає глобальні метадані, такі як загальна кількість токенів і авторитет + випуску (адреса, уповноважена створювати нові одиниці токенів). + +- [Токен-обліковий запис](#token-account) відстежує індивідуальну власність на + певну кількість токенів конкретного типу (облікового запису випуску токенів). + +> Наразі існує дві версії Програми Токенів: оригінальна +> [Програма Токенів](https://github.com/solana-labs/solana-program-library/tree/b1c44c171bc95e6ee74af12365cb9cbab68be76c/token/program) +> і +> [Програма Розширень Токенів](https://github.com/solana-labs/solana-program-library/tree/b1c44c171bc95e6ee74af12365cb9cbab68be76c/token/program-2022) +> (Token2022). Програма Розширень Токенів працює так само, як і оригінальна +> Програма Токенів, але з додатковими функціями і покращеннями. Для створення +> нових токенів рекомендовано використовувати Програму Розширень Токенів. + +## Основні моменти + +- Токени представляють право власності на взаємозамінні (змінні) або + невзаємозамінні (унікальні) активи. + +- Програма Токенів містить усі інструкції для взаємодії з токенами в мережі. + +- Програма Розширень Токенів — це нова версія Програми Токенів, яка включає + додаткові функції, зберігаючи основну функціональність. + +- Обліковий запис випуску токенів представляє унікальний токен у мережі і + зберігає глобальні метадані, такі як загальна кількість токенів. + +- Токен-обліковий запис відстежує індивідуальну власність на токени для певного + облікового запису випуску токенів. + +- Асоційований Токен-обліковий запис — це токен-обліковий запис, створений із + адреси, отриманої із адреси власника та адреси облікового запису випуску + токенів. + +## Програма Токенів + +[Програма Токенів](https://github.com/solana-labs/solana-program-library/tree/b1c44c171bc95e6ee74af12365cb9cbab68be76c/token/program) +містить всю логіку інструкцій для взаємодії з токенами в мережі (як +взаємозамінними, так і невзаємозамінними). Усі токени на Solana фактично є +[даними облікових записів](/docs/uk/core/accounts.md#data-account), якими +володіє Програма Токенів. + +Повний список інструкцій Програми Токенів можна знайти +[тут](https://github.com/solana-labs/solana-program-library/blob/b1c44c171bc95e6ee74af12365cb9cbab68be76c/token/program/src/instruction.rs). + +![Програма Токенів](/assets/docs/core/tokens/token-program.svg) + +Кілька найчастіше використовуваних інструкцій включають: + +- [`InitializeMint`](https://github.com/solana-labs/solana-program-library/blob/b1c44c171bc95e6ee74af12365cb9cbab68be76c/token/program/src/processor.rs#L29): + Створення нового облікового запису випуску токенів для представлення нового + типу токена. +- [`InitializeAccount`](https://github.com/solana-labs/solana-program-library/blob/b1c44c171bc95e6ee74af12365cb9cbab68be76c/token/program/src/processor.rs#L84): + Створення нового токен-облікового запису для зберігання одиниць певного типу + токенів (випуску). +- [`MintTo`](https://github.com/solana-labs/solana-program-library/blob/b1c44c171bc95e6ee74af12365cb9cbab68be76c/token/program/src/processor.rs#L522): + Створення нових одиниць певного типу токенів і додавання їх до + токен-облікового запису. Це збільшує кількість токенів і може виконуватися + лише авторитетом випуску облікового запису випуску токенів. +- [`Transfer`](https://github.com/solana-labs/solana-program-library/blob/b1c44c171bc95e6ee74af12365cb9cbab68be76c/token/program/src/processor.rs#L228): + Передача одиниць певного типу токенів із одного токен-облікового запису в + інший. + +### Обліковий запис випуску токенів + +Токени на Solana унікально ідентифікуються за адресою +[Облікового запису випуску токенів](https://github.com/solana-labs/solana-program-library/blob/b1c44c171bc95e6ee74af12365cb9cbab68be76c/token/program/src/state.rs#L18-L32), +яким володіє Програма Токенів. Цей обліковий запис фактично є глобальним +лічильником для певного токена і зберігає дані, такі як: + +- Загальна кількість: Загальна кількість токенів. +- Десяткові знаки: Точність токена у десяткових знаках. +- Авторитет випуску: Обліковий запис, уповноважений створювати нові одиниці + токенів, таким чином збільшуючи кількість. +- Авторитет замороження: Обліковий запис, уповноважений заморожувати токени, щоб + їх не можна було передати із "токен-облікових записів". + +![Обліковий запис випуску токенів](/assets/docs/core/tokens/mint-account.svg) + +Повна інформація, яка зберігається в кожному обліковому записі випуску токенів, +включає: + +```rust +pub struct Mint { + /// Optional authority used to mint new tokens. The mint authority may only + /// be provided during mint creation. If no mint authority is present + /// then the mint has a fixed supply and no further tokens may be + /// minted. + pub mint_authority: COption, + /// Total supply of tokens. + pub supply: u64, + /// Number of base 10 digits to the right of the decimal place. + pub decimals: u8, + /// Is `true` if this structure has been initialized + pub is_initialized: bool, + /// Optional authority to freeze token accounts. + pub freeze_authority: COption, +} +``` + +Для довідки, ось посилання на Solana Explorer для +[Облікового запису випуску USDC](https://explorer.solana.com/address/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v). + +### Токен-обліковий запис + +Для відстеження індивідуальної власності на кожну одиницю певного токена має +бути створений інший тип облікового запису даних, яким володіє Програма Токенів. +Цей обліковий запис називається +[Токен-обліковий запис](https://github.com/solana-labs/solana-program-library/blob/b1c44c171bc95e6ee74af12365cb9cbab68be76c/token/program/src/state.rs#L89-L110). + +Найчастіше згадувані дані, які зберігаються в Токен-обліковому записі, +включають: + +- **Випуск (Mint)**: Тип токена, одиниці якого зберігаються в Токен-обліковому + записі. +- **Власник (Owner)**: Обліковий запис, уповноважений передавати токени з + Токен-облікового запису. +- **Кількість (Amount)**: Кількість одиниць токена, які наразі зберігаються в + Токен-обліковому записі. + +![Токен-обліковий запис](/assets/docs/core/tokens/token-account.svg) + +Повна інформація, яка зберігається в кожному Токен-обліковому записі, включає: + +```rust +pub struct Account { + /// The mint associated with this account + pub mint: Pubkey, + /// The owner of this account. + pub owner: Pubkey, + /// The amount of tokens this account holds. + pub amount: u64, + /// If `delegate` is `Some` then `delegated_amount` represents + /// the amount authorized by the delegate + pub delegate: COption, + /// The account's state + pub state: AccountState, + /// If is_native.is_some, this is a native token, and the value logs the + /// rent-exempt reserve. An Account is required to be rent-exempt, so + /// the value is used by the Processor to ensure that wrapped SOL + /// accounts do not drop below this threshold. + pub is_native: COption, + /// The amount delegated + pub delegated_amount: u64, + /// Optional authority to close the account. + pub close_authority: COption, +} +``` + +Щоб гаманець міг володіти одиницями певного токена, потрібно створити +токен-обліковий запис для конкретного типу токена (випуску), який призначає +гаманець власником цього токен-облікового запису. Гаманець може створювати +кілька токен-облікових записів для одного і того ж типу токена, але кожен +токен-обліковий запис може належати лише одному гаманцю і зберігати одиниці лише +одного типу токена. + +![Взаємозв'язок облікових записів](/assets/docs/core/tokens/token-account-relationship.svg) + +> Зверніть увагу, що дані кожного Токен-облікового запису містять поле `owner`, +> яке використовується для визначення того, хто має авторитет над цим +> Токен-обліковим записом. Це окремо від власника програми, зазначеного у +> [AccountInfo](/docs/uk/core/accounts.md#accountinfo), яким є Програма Токенів +> для всіх Токен-облікових записів. + +### Асоційований токен-обліковий запис + +Щоб спростити процес визначення адреси токен-облікового запису для конкретного +випуску і власника, ми часто використовуємо Асоційовані Токен-облікові Записи. + +Асоційований токен-обліковий запис — це токен-обліковий запис, чия адреса +визначається детерміновано з використанням адреси власника і адреси облікового +запису випуску. Можна розглядати Асоційований токен-обліковий запис як +"стандартний" токен-обліковий запис для певного випуску і власника. + +Важливо розуміти, що Асоційований токен-обліковий запис не є окремим типом +токен-облікового запису. Це просто токен-обліковий запис із певною адресою. + +![Асоційований токен-обліковий запис](/assets/docs/core/tokens/associated-token-account.svg) + +Це вводить ключове поняття в розробці Solana: +[Програмно Виведена Адреса (PDA)](/docs/uk/core/pda.md). Концептуально PDA надає +детермінований спосіб генерації адреси з використанням заздалегідь визначених +вхідних даних. Це дозволяє нам легко знайти адресу облікового запису в +майбутньому. + +Ось +[приклад на Solana Playground](https://beta.solpg.io/656a2dd0fb53fa325bfd0c41), +який виводить адресу і власника Асоційованого токен-облікового запису USDC. Він +завжди генерує +[одну й ту саму адресу](https://explorer.solana.com/address/4kokFKCFMxpCpG41yLYkLEqXW8g1WPfCt2NC9KGivY6N) +для одного і того ж випуску і власника. + +```ts +import { getAssociatedTokenAddressSync } from "@solana/spl-token"; + +const associatedTokenAccountAddress = getAssociatedTokenAddressSync( + USDC_MINT_ADDRESS, + OWNER_ADDRESS, +); +``` + +Зокрема, адреса для Асоційованого токен-облікового запису виводиться за +допомогою наступних вхідних даних. Ось +[приклад на Solana Playground](https://beta.solpg.io/656a31d0fb53fa325bfd0c42), +який генерує ту саму адресу, що й у попередньому прикладі. + +```ts +import { PublicKey } from "@solana/web3.js"; + +const [PDA, bump] = PublicKey.findProgramAddressSync( + [ + OWNER_ADDRESS.toBuffer(), + TOKEN_PROGRAM_ID.toBuffer(), + USDC_MINT_ADDRESS.toBuffer(), + ], + ASSOCIATED_TOKEN_PROGRAM_ID, +); +``` + +Щоб два гаманці могли зберігати одиниці одного і того ж типу токена, кожен +гаманець потребує свого токен-облікового запису для конкретного облікового +запису випуску токенів. Зображення нижче демонструє, як виглядає ця структура +взаємозв'язку облікових записів. + +![Розширений взаємозв'язок облікових записів](/assets/docs/core/tokens/token-account-relationship-ata.svg) + +## Приклади роботи з токенами + +CLI [`spl-token`](https://docs.anza.xyz/cli) можна використовувати для +експериментів з SPL токенами. У прикладах нижче ми використовуватимемо +[Solana Playground](https://beta.solpg.io/) для виконання CLI-команд прямо в +браузері без необхідності встановлення CLI локально. + +Створення токенів і облікових записів вимагає SOL для депозитів за оренду +облікових записів та оплати транзакційних комісій. Якщо ви вперше використовуєте +Solana Playground, створіть гаманець у Playground і виконайте команду +`solana airdrop` у терміналі Playground. Ви також можете отримати SOL для +devnet, використовуючи публічний [веб-фасет](https://faucet.solana.com/). + +```sh +solana airdrop 2 +``` + +Run `spl-token --help` for a full description of available commands. + +```sh +spl-token --help +``` + +Крім того, ви можете встановити CLI `spl-token` локально, використовуючи +наступну команду. Для цього спочатку потрібно +[встановити Rust](https://rustup.rs/). + +> У наступних розділах адреси облікових записів, які відображаються під час +> виконання CLI-команд, можуть відрізнятися від прикладів, наведених нижче. Будь +> ласка, використовуйте адреси, які відображаються у вашому терміналі +> Playground, під час виконання команд. Наприклад, адреса, отримана в результаті +> виконання `create-token`, є обліковим записом випуску токенів, де ваш гаманець +> Playground призначений авторитетом випуску. + +### Створення нового токена + +Щоб створити новий токен ([обліковий запис випуску токенів](#mint-account)), +виконайте наступну команду в терміналі Solana Playground. + +```sh +spl-token create-token +``` + +Ви повинні побачити результат, подібний до наведеного нижче. Ви можете +переглянути деталі як токена, так і транзакції у +[Solana Explorer](https://explorer.solana.com/?cluster=devnet), використовуючи +`Address` (адресу) та `Signature` (підпис). + +У прикладі результату нижче унікальний ідентифікатор (адреса) нового токена — +`99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg`. + +```shell filename="Terminal Output" /99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg/ +Creating token 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg + +Address: 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg +Decimals: 9 + +Signature: 44fvKfT1ezBUwdzrCys3fvCdFxbLMnNvBstds76QZyE6cXag5NupBprSXwxPTzzjrC3cA6nvUZaLFTvmcKyzxrm1 +``` + +Нові токени спочатку мають нульовий запас. Ви можете перевірити поточний запас +токена, використовуючи наступну команду: + +```sh +spl-token supply +``` + +Запуск команди `supply` для новоствореного токена поверне значення `0`: + +```sh /99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg/ +spl-token supply 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg +``` + +У своїй основі створення нового облікового запису випуску токенів (Mint Account) +вимагає надсилання транзакції з двома інструкціями. Ось приклад на Javascript у +[Solana Playground](https://beta.solpg.io/660ce32ecffcf4b13384d00f). + +1. Виклик Системної Програми для створення нового облікового запису з достатнім + обсягом пам'яті для даних облікового запису випуску токенів, а потім передача + власності Програмі Токенів. + +2. Виклик Програми Токенів для ініціалізації даних нового облікового запису як + облікового запису випуску токенів. + +### Створення Токен-облікового запису + +Щоб зберігати одиниці певного токена, вам потрібно спочатку створити +[токен-обліковий запис](#token-account). Для створення нового токен-облікового +запису скористайтеся наступною командою: + +```sh +spl-token create-account [OPTIONS] +``` + +Наприклад, виконання наступної команди в терміналі Solana Playground: + +````sh /99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg/ +spl-token create-account 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg +```: +Виведе наступний результат +- `AfB7uwBEsGtrrBqPTVqEgzWed5XdYfM1psPNLmf7EeX9`це адреса токен-облікового запису, створеного для зберігання одиниць токена, +вказаного в команді `create-account`. + +```shell filename="Terminal Output" /AfB7uwBEsGtrrBqPTVqEgzWed5XdYfM1psPNLmf7EeX9/ +Creating account AfB7uwBEsGtrrBqPTVqEgzWed5XdYfM1psPNLmf7EeX9 + +Signature: 2BtrynuCLX9CNofFiaw6Yzbx6hit66pup9Sk7aFjwU2NEbFz7NCHD9w9sWhrCfEd73XveAGK1DxFpJoQZPXU9tS1 +```` + +За замовчуванням команда `create-account` створює +[асоційований токен-обліковий запис](#associated-token-account) з адресою вашого +гаманця як власника токен-облікового запису. + +Ви можете створити токен-обліковий запис з іншим власником, використовуючи +наступну команду: + +```sh +spl-token create-account --owner +``` + +Наприклад, виконання наступної команди: + +```sh /2i3KvjDCZWxBsqcxBHpdEaZYQwQSYE6LXUMx5VjY5XrR/ +spl-token create-account --owner 2i3KvjDCZWxBsqcxBHpdEaZYQwQSYE6LXUMx5VjY5XrR 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg +``` + +Виведе наступний результат: + +- `Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt` — це адреса токен-облікового + запису, створеного для зберігання одиниць токена, вказаного в команді + `create-account` (`99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg`), і який + належить адресі, вказаній після прапора `--owner` + (`2i3KvjDCZWxBsqcxBHpdEaZYQwQSYE6LXUMx5VjY5XrR`). Це корисно, коли вам + потрібно створити токен-обліковий запис для іншого користувача. + +```shell filename="Terminal Output" /Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt/ +Creating account Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt + +Signature: 44vqKdfzspT592REDPY4goaRJH3uJ3Ce13G4BCuUHg35dVUbHuGTHvqn4ZjYF9BGe9QrjMfe9GmuLkQhSZCBQuEt +``` + +За лаштунками створення Асоційованого токен-облікового запису потребує однієї +інструкції, яка викликає +[Програму Асоційованих Токенів](https://github.com/solana-labs/solana-program-library/tree/b1c44c171bc95e6ee74af12365cb9cbab68be76c/associated-token-account/program/src). +Ось приклад на Javascript у +[Solana Playground](https://beta.solpg.io/660ce868cffcf4b13384d011). + +Програма Асоційованих Токенів використовує +[Перехресні Виклики Програм (CPI)](/docs/uk/core/cpi.md) для виконання +наступного: + +- [Виклик Системної Програми](https://github.com/solana-labs/solana-program-library/blob/b1c44c171bc95e6ee74af12365cb9cbab68be76c/associated-token-account/program/src/tools/account.rs#L19) + для створення нового облікового запису, використовуючи надану PDA як адресу + нового облікового запису. +- [Виклик Програми Токенів](https://github.com/solana-labs/solana-program-library/blob/b1c44c171bc95e6ee74af12365cb9cbab68be76c/associated-token-account/program/src/processor.rs#L138-L161) + для ініціалізації даних токен-облікового запису для нового облікового запису. + +Крім того, створення нового токен-облікового запису за допомогою випадково +згенерованої пари ключів (не Асоційованого токен-облікового запису) потребує +надсилання транзакції з двома інструкціями. Ось приклад на Javascript у +[Solana Playground](https://beta.solpg.io/660ce716cffcf4b13384d010). + +1. Виклик Системної Програми для створення нового облікового запису з достатнім + обсягом пам'яті для даних токен-облікового запису, а потім передача власності + Програмі Токенів. + +2. Виклик Програми Токенів для ініціалізації даних нового облікового запису як + токен-облікового запису. + +### Випуск токенів + +Щоб створити нові одиниці токена, використовуйте наступну команду: + +```sh +spl-token mint [OPTIONS] [--] [RECIPIENT_TOKEN_ACCOUNT_ADDRESS] +``` + +Наприклад, виконання наступної команди: + +```sh +spl-token mint 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg 100 +``` + +Виведе наступний результат: + +- `99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg` — це адреса облікового запису + випуску токенів, для якого випускаються токени (збільшуючи загальну + кількість). + +- `AfB7uwBEsGtrrBqPTVqEgzWed5XdYfM1psPNLmf7EeX9` — це адреса токен-облікового + запису вашого гаманця, до якого випускаються одиниці токена (збільшуючи + кількість). + +```shell filename="Terminal Output" /99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg/ /AfB7uwBEsGtrrBqPTVqEgzWed5XdYfM1psPNLmf7EeX9/ +Minting 100 tokens + Token: 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg + Recipient: AfB7uwBEsGtrrBqPTVqEgzWed5XdYfM1psPNLmf7EeX9 + +Signature: 2NJ1m7qCraPSBAVxbr2ssmWZmBU9Jc8pDtJAnyZsZJRcaYCYMqq1oRY1gqA4ddQno3g3xcnny5fzr1dvsnFKMEqG +``` + +Щоб випустити токени до іншого токен-облікового запису, вкажіть адресу +потрібного облікового запису одержувача токенів. + +Наприклад, виконання наступної команди: + +```sh /Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt/ +spl-token mint 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg 100 -- Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt +``` + +Повертає наступний результат: + +- 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg — це адреса облікового запису + випуску токенів, для якого випускаються токени (збільшуючи загальну + кількість). + +- Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt — це адреса токен-облікового + запису, до якого випускаються одиниці токена (збільшуючи кількість). + +```shell filename="Terminal Output" /99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg/ /Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt/ +Minting 100 tokens + Token: 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg + Recipient: Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt + +Signature: 3SQvNM3o9DsTiLwcEkSPT1Edr14RgE2wC54TEjonEP2swyVCp2jPWYWdD6RwXUGpvDNUkKWzVBZVFShn5yntxVd7 +``` + +За лаштунками створення нових одиниць токена потребує виклику інструкції +`MintTo` у Програмі Токенів. Ця інструкція повинна бути підписана авторитетом +випуску. Інструкція випускає нові одиниці токена до Токен-облікового запису та +збільшує загальну кількість у Обліковому записі випуску токенів. Ось приклад на +Javascript у +[Solana Playground](https://beta.solpg.io/660cea45cffcf4b13384d012). + +### Передача токенів + +Щоб передати одиниці токена між двома токен-обліковими записами, використовуйте +наступну команду: + +```sh +spl-token transfer [OPTIONS] +``` + +Наприклад, виконання наступної команди: + +```sh +spl-token transfer 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg 100 Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt +``` + +Повертає наступний результат: + +- `AfB7uwBEsGtrrBqPTVqEgzWed5XdYfM1psPNLmf7EeX9` — це адреса токен-облікового + запису, з якого передаються токени. Це буде адреса вашого токен-облікового + запису для вказаного токена, який передається. + +- `Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt` — це адреса токен-облікового + запису, до якого передаються токени. + +```shell filename="Terminal Output" /AfB7uwBEsGtrrBqPTVqEgzWed5XdYfM1psPNLmf7EeX9/ /Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt/ +Transfer 100 tokens + Sender: AfB7uwBEsGtrrBqPTVqEgzWed5XdYfM1psPNLmf7EeX9 + Recipient: Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt + +Signature: 5y6HVwV8V2hHGLTVmTmdySRiEUCZnWmkasAvJ7J6m7JR46obbGKCBqUFgLpZu5zQGwM4Xy6GZ4M5LKd1h6Padx3o +``` + +За лаштунками, передача токенів потребує виклику інструкції `Transfer` у +Програмі Токенів. Ця інструкція повинна бути підписана власником +токен-облікового запису відправника. Інструкція передає одиниці токена з одного +Токен-облікового запису до іншого. Ось приклад на Javascript у +[Solana Playground](https://beta.solpg.io/660ced84cffcf4b13384d013). + +Важливо розуміти, що як у відправника, так і у одержувача повинні існувати +токен-облікові записи для конкретного типу токена, який передається. Відправник +може додати додаткові інструкції до транзакції для створення токен-облікового +запису одержувача, який, як правило, є Асоційованим Токен-обліковим записом. + +### Створення метаданих токенів + +Програма Розширень Токенів дозволяє додавати настроювані метадані (наприклад, +назву, символ, посилання на зображення) безпосередньо до Облікового запису +випуску токенів. + + + Щоб використовувати параметри CLI для розширень токенів, переконайтеся, що ви маєте + локально встановлений CLI, версії 3.4.0 або пізнішої: + + `cargo install --version 3.4.0 spl-token-cli` + + +Щоб створити новий токен із увімкненим розширенням метаданих, скористайтеся +наступною командою: + +```sh +spl-token create-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb +--enable-metadata +``` + +Команда повертає наступний результат: + +- `BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczP` — це адреса нового токена, + створеного з увімкненим розширенням метаданих. + +```shell filename="Terminal Output" /BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczP/ +Creating token BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczP under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb +To initialize metadata inside the mint, please run `spl-token initialize-metadata BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczP `, and sign with the mint authority. + +Address: BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczP +Decimals: 9 + +Signature: 5iQofFeXdYhMi9uTzZghcq8stAaa6CY6saUwcdnELST13eNSifiuLbvR5DnRt311frkCTUh5oecj8YEvZSB3wfai +``` + +Після створення нового токена з увімкненим розширенням метаданих використовуйте +наступну команду для ініціалізації метаданих: + +```sh +spl-token initialize-metadata + +``` + +Токен URI зазвичай є посиланням на позаблокові метадані, які ви хочете +асоціювати з токеном. Приклад формату JSON можна знайти +[тут](https://raw.githubusercontent.com/solana-developers/opos-asset/main/assets/DeveloperPortal/metadata.json). + +Наприклад, виконання наступної команди дозволить зберегти додаткові метадані +безпосередньо в зазначеному обліковому записі випуску токенів: + +```sh /BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczP/ +spl-token initialize-metadata BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczP "TokenName" "TokenSymbol" "https://raw.githubusercontent.com/solana-developers/opos-asset/main/assets/DeveloperPortal/metadata.json" +``` + +Ви можете знайти адресу облікового запису випуску токенів у експлорері, щоб +переглянути метадані. Наприклад, ось токен, створений із увімкненим розширенням +метаданих, у експлорері +[SolanaFm](https://solana.fm/address/BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczP?cluster=devnet-solana). + +Дізнатися більше можна у +[Посібнику з Розширення Метаданих](https://solana.com/developers/guides/token-extensions/metadata-pointer). +Деталі щодо різних Розширень Токенів ви знайдете у +[Посібнику Початківця з Розширень Токенів](https://solana.com/developers/guides/token-extensions/getting-started) +та [документації SPL](https://spl.solana.com/token-2022/extensions). diff --git a/docs/locales/uk/core/transactions.md b/docs/locales/uk/core/transactions.md new file mode 100644 index 000000000..400dfe83b --- /dev/null +++ b/docs/locales/uk/core/transactions.md @@ -0,0 +1,407 @@ +--- +title: "Транзакції та Інструкції" +sidebarSortOrder: 2 +description: + Дізнайтеся про транзакції та інструкції Solana — основні будівельні блоки для + взаємодії з блокчейном Solana. Зрозумійте структуру транзакцій і створення + інструкцій із практичними прикладами. +--- + +У Solana ми надсилаємо [транзакції](/docs/uk/core/transactions#transaction), щоб +взаємодіяти з мережею. Транзакції включають одну або більше +[інструкцій](/docs/uk/core/transactions#instruction), кожна з яких представляє +конкретну операцію, що має бути оброблена. Логіка виконання інструкцій +зберігається в [програмах](/docs/uk/core/programs), розгорнутих у мережі Solana, +і кожна програма зберігає свій набір інструкцій. + +Нижче наведено основні деталі щодо виконання транзакцій: + +- Порядок виконання: Якщо транзакція містить декілька інструкцій, вони + обробляються у порядку, в якому були додані до транзакції. +- Атомарність: Транзакція є атомарною, тобто вона або повністю виконується з + успішною обробкою всіх інструкцій, або повністю провалюється. Якщо будь-яка + інструкція у транзакції не вдається, жодна з інструкцій не буде виконана. + +Для простоти можна уявити транзакцію як запит на обробку однієї або кількох +інструкцій. + +![Спрощена транзакція](/assets/docs/core/transactions/transaction-simple.svg) + +Уявіть транзакцію як конверт, де кожна інструкція — це документ, який ви +заповнюєте та кладете у конверт. Потім ми відправляємо конверт для обробки +документів, так само, як відправляємо транзакцію в мережу для обробки наших +інструкцій. + +## Основні моменти + +- Транзакції Solana складаються з інструкцій, які взаємодіють із різними + програмами в мережі, де кожна інструкція представляє конкретну операцію. + +- Кожна інструкція вказує програму для виконання інструкції, облікові записи, + необхідні для інструкції, та дані, потрібні для виконання інструкції. + +- Інструкції в транзакції обробляються в порядку, в якому вони вказані. + +- Транзакції є атомарними, тобто або всі інструкції успішно обробляються, або + вся транзакція провалюється. + +- Максимальний розмір транзакції становить 1232 байти. + +## Простий приклад + +Нижче наведено діаграму, яка представляє транзакцію з однією інструкцією для +переказу SOL від відправника до отримувача. + +Індивідуальні "гаманці" у Solana є обліковими записами, якими володіє +[Системна програма](/docs/uk/core/accounts#system-program). Як частина +[моделі облікових записів Solana](/docs/uk/core/accounts), лише програма, якій +належить обліковий запис, може змінювати дані цього облікового запису. + +Тому для переказу SOL із облікового запису "гаманця" необхідно надіслати +транзакцію для виклику інструкції переказу у Системній програмі. + +![Переказ SOL](/assets/docs/core/transactions/sol-transfer.svg) + +Обліковий запис відправника має бути доданий як підписант (`is_signer`) до +транзакції, щоб схвалити списання балансу лампортів. Обидва облікові записи, +відправник і отримувач, мають бути змінюваними (`is_writable`), оскільки +інструкція змінює баланс лампортів для обох облікових записів. + +Після відправлення транзакції викликається Системна програма для обробки +інструкції переказу. Потім Системна програма оновлює баланс лампортів для обох +облікових записів відповідно. + +![Процес переказу SOL](/assets/docs/core/transactions/sol-transfer-process.svg) + +### Простий переказ SOL + +Ось приклад із +[Solana Playground](https://beta.solpg.io/656a0ea7fb53fa325bfd0c3e), який +демонструє, як створити інструкцію переказу SOL за допомогою методу +`SystemProgram.transfer`: + +```typescript +// Визначення суми переказу +const transferAmount = 0.01; // 0.01 SOL + +// Створення інструкції для переказу SOL з wallet_1 до wallet_2 +const transferInstruction = SystemProgram.transfer({ + fromPubkey: sender.publicKey, + toPubkey: receiver.publicKey, + lamports: transferAmount * LAMPORTS_PER_SOL, // Конвертація transferAmount у лампорти +}); + +// Додавання інструкції переказу до нової транзакції +const transaction = new Transaction().add(transferInstruction); +``` + +Запустіть скрипт і перевірте деталі транзакції, що виводяться в консоль. У +наступних розділах ми розглянемо, що відбувається "під капотом". + +## Транзакція + +Транзакція Solana +[transaction](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/sdk/src/transaction/mod.rs#L173) +складається з: + +1. [Підписів](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/sdk/src/signature.rs#L27): + Масиву підписів, включених у транзакцію. +2. [Повідомлення](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/sdk/program/src/message/legacy.rs#L110): + Переліку інструкцій, які будуть оброблятися атомарно. + +![Формат транзакції](/assets/docs/core/transactions/tx_format.png) + +Структура повідомлення транзакції складається з: + +- [Заголовка повідомлення](/docs/uk/core/transactions#message-header): Вказує + кількість підписантів та облікових записів тільки для читання. +- [Масиву адрес облікових записів](/docs/uk/core/transactions#array-of-account-addresses): + Масив адрес облікових записів, необхідних для інструкцій у транзакції. +- [Недавнього блоку хешу](/docs/uk/core/transactions#recent-blockhash): + Використовується як мітка часу для транзакції. +- [Масиву інструкцій](/docs/uk/core/transactions#array-of-instructions): Масив + інструкцій, які слід виконати. + +![Повідомлення транзакції](/assets/docs/core/transactions/legacy_message.png) + +### Розмір транзакції + +Мережа Solana дотримується максимального розміру пакета (MTU) у 1280 байт, що +відповідає [MTU IPv6](https://en.wikipedia.org/wiki/IPv6_packet). Це забезпечує +швидку та надійну передачу інформації у кластері через UDP. Після врахування +необхідних заголовків (40 байт для IPv6 та 8 байт для заголовка фрагмента), +[1232 байти залишаються для даних пакета](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/sdk/src/packet.rs#L16-L21), +таких як серіалізовані транзакції. + +Це означає, що загальний розмір транзакції Solana обмежений 1232 байтами. +Підписи та повідомлення у комбінації не можуть перевищувати цей ліміт. + +- Підписи: Кожен підпис займає 64 байти. Кількість підписів може варіювати + залежно від вимог транзакції. +- Повідомлення: Повідомлення включає інструкції, облікові записи та додаткові + метадані. Кожен обліковий запис займає 32 байти. Загальний розмір облікових + записів плюс метадані може варіювати залежно від інструкцій у транзакції. + +![Формат транзакції](/assets/docs/core/transactions/issues_with_legacy_txs.png) + +### Заголовок повідомлення + +[Заголовок повідомлення](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/sdk/program/src/message/mod.rs#L96) +вказує на привілеї облікових записів, включених у масив адрес транзакції. Він +складається з трьох байтів, кожен з яких містить ціле число типу u8, що +колективно вказує: + +1. Кількість необхідних підписів для транзакції. +2. Кількість облікових записів тільки для читання, які потребують підписів. +3. Кількість облікових записів тільки для читання, які не потребують підписів. + +![Заголовок повідомлення](/assets/docs/core/transactions/message_header.png) + +### Формат компактного масиву + +Компактний масив у контексті повідомлення транзакції посилається на масив, +серіалізований у наступному форматі: + +1. Довжина масиву, закодована як + [compact-u16](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/sdk/program/src/short_vec.rs). +2. Окремі елементи масиву, перераховані послідовно після закодованої довжини. + +![Формат компактного масиву](/assets/docs/core/transactions/compact_array_format.png) + +Цей метод кодування використовується для вказівки довжин як +[масиву адрес облікових записів](/docs/uk/core/transactions#array-of-account-addresses), +так і [масиву інструкцій](/docs/uk/core/transactions#array-of-instructions) у +повідомленні транзакції. + +### Масив адрес облікових записів + +Повідомлення транзакції включає масив, що містить усі +[адреси облікових записів](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/sdk/program/src/message/legacy.rs#L119), +необхідні для інструкцій у транзакції. + +Цей масив починається з кодування +[compact-u16](/docs/uk/core/transactions#compact-array-format) довжини масиву, +після чого йдуть адреси, впорядковані за привілеями облікових записів. Метадані +в заголовку повідомлення використовуються для визначення кількості облікових +записів у кожному розділі. + +- Облікові записи, що є змінюваними та підписантами. +- Облікові записи тільки для читання, що є підписантами. +- Облікові записи, що є змінюваними, але не підписантами. +- Облікові записи тільки для читання, що не є підписантами. + +![Компактний масив адрес облікових записів](/assets/docs/core/transactions/compat_array_of_account_addresses.png) + +### Недавній блок-хеш + +Усі транзакції включають +[недавній блок-хеш](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/sdk/program/src/message/legacy.rs#L122), +який використовується як мітка часу для транзакції. Блок-хеш запобігає +дублюванню транзакцій і виключає застарілі транзакції. + +Максимальний вік блок-хеша для транзакції становить 150 блоків (~1 хвилина, якщо +час блоку складає 400 мс). Якщо блок-хеш транзакції старіший за 150 блоків від +останнього блок-хеша, вона вважається протермінованою. Це означає, що +транзакції, які не були оброблені вчасно, ніколи не будуть виконані. + +Ви можете скористатися RPC-методом +[`getLatestBlockhash`](/docs/uk/rpc/http/getlatestblockhash), щоб отримати +поточний блок-хеш і останню висоту блоку, на якій блок-хеш залишатиметься +дійсним. Ось приклад у +[Solana Playground](https://beta.solpg.io/661a06e1cffcf4b13384d046). + +### Масив інструкцій + +Повідомлення транзакції включає масив усіх +[інструкцій](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/sdk/program/src/message/legacy.rs#L128), +які запитуються для обробки. Інструкції у повідомленні транзакції мають формат +[CompiledInstruction](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/sdk/program/src/instruction.rs#L633). + +Подібно до масиву адрес облікових записів, цей компактний масив починається з +кодування [compact-u16](/docs/uk/core/transactions#compact-array-format) +кількості інструкцій, після чого йде масив інструкцій. Кожна інструкція в масиві +вказує наступну інформацію: + +1. **Program ID**: Ідентифікатор програми в мережі, яка оброблятиме інструкцію. + Це представлено у вигляді індексу типу u8, що вказує на адресу програми у + масиві адрес облікових записів. +2. **Компактний масив індексів адрес облікових записів**: Масив індексів типу + u8, що вказує на масив адрес облікових записів для кожного облікового запису, + потрібного для інструкції. +3. **Компактний масив байтів даних**: Масив байтів типу u8, специфічний для + викликаної програми. Ці дані вказують, яку інструкцію викликати у програмі, + разом із будь-якими додатковими даними, потрібними для виконання інструкції + (наприклад, аргументами функції). + +![Компактний масив інструкцій](/assets/docs/core/transactions/compact_array_of_ixs.png) + +### Приклад структури транзакції + +Нижче наведено приклад структури транзакції, яка включає одну інструкцію для +[передачі SOL](/docs/uk/core/transactions#basic-example). Тут показано деталі +повідомлення, включаючи заголовок, ключі облікових записів, блок-хеш та +інструкції, разом із підписом для транзакції. + +- `header`: Містить дані, які використовуються для вказання привілеїв + читання/запису та підписання у масиві `accountKeys`. +- `accountKeys`: Масив, що включає адреси облікових записів для всіх інструкцій + у транзакції. +- `recentBlockhash`: Блок-хеш, включений у транзакцію під час її створення. +- `instructions`: Масив, що включає всі інструкції у транзакції. Кожен `account` + та `programIdIndex` в інструкції посилаються на масив `accountKeys` за + індексом. +- `signatures`: Масив, що включає підписи для всіх облікових записів, потрібних + як підписанти для інструкцій у транзакції. Підпис створюється шляхом + підписання повідомлення транзакції за допомогою відповідного приватного ключа + для облікового запису. + +```json +"transaction": { + "message": { + "header": { + "numReadonlySignedAccounts": 0, + "numReadonlyUnsignedAccounts": 1, + "numRequiredSignatures": 1 + }, + "accountKeys": [ + "3z9vL1zjN6qyAFHhHQdWYRTFAcy69pJydkZmSFBKHg1R", + "5snoUseZG8s8CDFHrXY2ZHaCrJYsW457piktDmhyb5Jd", + "11111111111111111111111111111111" + ], + "recentBlockhash": "DzfXchZJoLMG3cNftcf2sw7qatkkuwQf4xH15N5wkKAb", + "instructions": [ + { + "accounts": [ + 0, + 1 + ], + "data": "3Bxs4NN8M2Yn4TLb", + "programIdIndex": 2, + "stackHeight": null + } + ], + "indexToProgramIds": {} + }, + "signatures": [ + "5LrcE2f6uvydKRquEJ8xp19heGxSvqsVbcqUeFoiWbXe8JNip7ftPQNTAVPyTK7ijVdpkzmKKaAQR7MWMmujAhXD" + ] + } +``` + +## Інструкція + +[Інструкція](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/sdk/program/src/instruction.rs#L329) +— це запит на виконання конкретної дії в мережі. Це найменша неподільна одиниця +логіки виконання у [програмі](/docs/uk/core/accounts#program-account). + +При створенні інструкції для додавання до транзакції кожна інструкція повинна +включати наступну інформацію: + +- **Адреса програми**: Вказує програму, яку буде викликано. +- **Облікові записи**: Перелік кожного облікового запису, з якого інструкція + читає або до якого пише, включаючи інші програми, за допомогою структури + `AccountMeta`. +- **Дані інструкції**: Масив байтів, що вказує, який + [обробник інструкцій](/docs/uk/terminology#instruction-handler) викликати у + програмі, а також будь-які додаткові дані, необхідні обробнику інструкцій + (аргументи функції). + +![Інструкція транзакції](/assets/docs/core/transactions/instruction.svg) + +### AccountMeta + +Для кожного облікового запису, необхідного для інструкції, потрібно вказати +наступну інформацію: + +- `pubkey`: Адреса облікового запису в мережі. +- `is_signer`: Вказує, чи є обліковий запис підписантом у транзакції. +- `is_writable`: Вказує, чи будуть змінені дані облікового запису. + +Ця інформація називається +[AccountMeta](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/sdk/program/src/instruction.rs#L539). + +![AccountMeta](/assets/docs/core/transactions/accountmeta.svg) + +Завдяки вказанню всіх облікових записів, необхідних для інструкції, і +зазначенню, які з них можуть бути змінені, транзакції можуть виконуватися +паралельно. + +Наприклад, дві транзакції, які не включають жодних облікових записів, що +записують в той самий стан, можуть виконуватися одночасно. + +### Приклад структури інструкції + +Нижче наведено приклад структури інструкції для +[передачі SOL](/docs/uk/core/transactions#basic-examples), яка деталізує ключі +облікових записів, ідентифікатор програми та дані, необхідні для інструкції. + +- `keys`: Містить `AccountMeta` для кожного облікового запису, необхідного для + інструкції. +- `programId`: Адреса програми, яка містить логіку виконання для викликаної + інструкції. +- `data`: Дані інструкції у вигляді буфера байтів. + +``` +{ + "keys": [ + { + "pubkey": "3z9vL1zjN6qyAFHhHQdWYRTFAcy69pJydkZmSFBKHg1R", + "isSigner": true, + "isWritable": true + }, + { + "pubkey": "BpvxsLYKQZTH42jjtWHZpsVSa7s6JVwLKwBptPSHXuZc", + "isSigner": false, + "isWritable": true + } + ], + "programId": "11111111111111111111111111111111", + "data": [2,0,0,0,128,150,152,0,0,0,0,0] +} +``` + +## Розширений приклад + +Деталі створення програмних інструкцій часто приховуються клієнтськими +бібліотеками. Проте, якщо такої бібліотеки немає, завжди можна вручну створити +інструкцію. + +### Ручна передача SOL + +Ось приклад на +[Solana Playground](https://beta.solpg.io/656a102efb53fa325bfd0c3f), який +демонструє, як вручну створити інструкцію для передачі SOL: + +```typescript +// Define the amount to transfer +const transferAmount = 0.01; // 0.01 SOL + +// Instruction index for the SystemProgram transfer instruction +const transferInstructionIndex = 2; + +// Create a buffer for the data to be passed to the transfer instruction +const instructionData = Buffer.alloc(4 + 8); // uint32 + uint64 +// Write the instruction index to the buffer +instructionData.writeUInt32LE(transferInstructionIndex, 0); +// Write the transfer amount to the buffer +instructionData.writeBigUInt64LE(BigInt(transferAmount * LAMPORTS_PER_SOL), 4); + +// Manually create a transfer instruction for transferring SOL from sender to receiver +const transferInstruction = new TransactionInstruction({ + keys: [ + { pubkey: sender.publicKey, isSigner: true, isWritable: true }, + { pubkey: receiver.publicKey, isSigner: false, isWritable: true }, + ], + programId: SystemProgram.programId, + data: instructionData, +}); + +// Add the transfer instruction to a new transaction +const transaction = new Transaction().add(transferInstruction); +``` + +Під капотом [простий приклад](/docs/uk/core/transactions#simple-sol-transfer) з +використанням методу `SystemProgram.transfer` функціонально еквівалентний більш +детальному прикладу вище. Метод `SystemProgram.transfer` просто приховує деталі +створення буфера даних інструкції та `AccountMeta` для кожного облікового +запису, необхідного для інструкції. diff --git a/docs/locales/uk/economics/index.md b/docs/locales/uk/economics/index.md new file mode 100644 index 000000000..512f698e6 --- /dev/null +++ b/docs/locales/uk/economics/index.md @@ -0,0 +1,52 @@ +--- +sidebarLabel: Економіка +title: Огляд Економіки Solana +altRoutes: + - /docs/uk/intro/economics +sidebarSortOrder: 5 +--- + +**Може бути змінено.** + +Криптоекономічна система Solana розроблена для сприяння здоровій, довгостроковій +самопідтримуваній економіці, в якій стимули учасників узгоджуються із +забезпеченням безпеки та децентралізації мережі. Основними учасниками цієї +економіки є валідаційні клієнти. Їхній внесок у мережу, перевірка стану та +відповідні механізми стимулювання розглядаються нижче. + +Основними каналами винагород для учасників є винагороди, засновані на протоколі, +та транзакційні комісії. Винагороди, засновані на протоколі, генеруються за +рахунок інфляційного випуску згідно з визначеним протоколом графіком інфляції. +Ці винагороди становитимуть загальну винагороду на основі протоколу, яка буде +надаватися валідаційним клієнтам, решта забезпечується за рахунок транзакційних +комісій. У перші дні роботи мережі ймовірно, що винагороди, засновані на +протоколі, розподілені згідно з попередньо визначеним графіком випуску, стануть +основним стимулом для учасників мережі. + +Ці винагороди розраховуються за кожну епоху і розподіляються серед активного +делегованого стейку та набору валідаторів (з урахуванням комісії валідаторів). +Як описано нижче, річний рівень інфляції ґрунтується на визначеному +дисінфляційному графіку. Це забезпечує мережі передбачуваність поставок, що +підтримує довгострокову економічну стабільність та безпеку. + +Транзакційні комісії є переказами між учасниками, що додаються до взаємодії з +мережею як стимул та компенсація за включення і виконання запропонованої +транзакції. Також обговорюється механізм довгострокової економічної стабільності +та захисту від розгалужень через часткове спалювання кожної транзакційної +комісії. + +Спочатку подано огляд дизайну інфляції. Цей розділ починається з визначення та +уточнення [Термінології](/docs/uk/economics/inflation/terminology.md), що часто +використовується у подальшому обговоренні інфляції та пов'язаних компонентів. +Далі ми окреслюємо запропонований +[Графік Інфляції](/docs/uk/economics/inflation/inflation_schedule.md) Solana, +тобто конкретні параметри, які унікально визначають інфляційний випуск, +керований протоколом, з плином часу. Наступним є короткий розділ про +[Скориговану Доходність Стейкінгу](/docs/uk/economics/inflation/_adjusted_staking_yield.md) +і те, як розбавлення токенів може вплинути на поведінку стейкінгу. + +Огляд [Транзакційних Комісій](/docs/uk/core/fees.md#transaction-fees) у Solana +супроводжується обговоренням +[Економіки Оренди для Зберігання](/docs/uk/core/fees.md#rent), у якому +описується реалізація орендної плати за зберігання для обліку зовнішніх витрат +на підтримання активного стану реєстру. diff --git a/docs/locales/uk/economics/inflation/_adjusted_staking_yield.md b/docs/locales/uk/economics/inflation/_adjusted_staking_yield.md new file mode 100644 index 000000000..566f3676d --- /dev/null +++ b/docs/locales/uk/economics/inflation/_adjusted_staking_yield.md @@ -0,0 +1,87 @@ +--- +title: Скоригована Дохідність Стейкінгу +--- + +### Дилюція Токенів + +Подібним чином ми можемо розглянути очікувану _Дилюцію Стейкінгу_ (тобто +_Скориговану Дохідність Стейкінгу_) та _Дилюцію Нестейкінгованих Токенів_, як +було визначено раніше. У цьому контексті _дилюція_ означає зміну фракційного +представлення (тобто частки власності) набору токенів у рамках більшого пулу. У +цьому сенсі дилюція може бути позитивною (збільшення частки власності, +стейкінгова дилюція / _Скоригована Дохідність Стейкінгу_) або негативною +(зменшення частки власності, нестейкінгова дилюція). + +Нас цікавить відносна зміна власності стейкінгованих і нестейкінгованих токенів +у міру збільшення загального пулу токенів через інфляційний випуск. Як було +зазначено, цей випуск розподіляється лише серед власників стейкінгованих +токенів, збільшуючи їх частку у _Загальному Поточному Обсязі_. + +Продовжуючи з тими ж параметрами _Графіку Інфляції_, що й раніше, ми бачимо +зростання частки стейкінгового пулу, як показано нижче. + +![Графік зростання частки стейкінгового пулу](/assets/docs/economics/example_staked_supply_w_range_initial_stake.png) + +Через цю відносну зміну у представництві частка стейкінгу будь-якого власника +токенів також змінюється як функція _Графіку Інфляції_ та частки стейкінгованих +токенів. + +### Розрахунок Дилюції Нестейкінгованих Токенів + +Особливий інтерес викликає _Дилюція Нестейкінгованих Токенів_, або $D_{us}$. У +випадку нестейкінгованих токенів дилюція залежить лише від _Графіку Інфляції_, +оскільки кількість нестейкінгованих токенів не змінюється з часом. + +$$ +\begin{aligned} + D_{us} &= \left( \frac{P_{us}(t_{1}) - P_{us}(t_{0})}{P_{us}(t_{0})} \right)\\ + &= \left( \frac{ \left( \frac{SOL_{us}(t_{2})}{SOL_{total}(t_{2})} \right) - \left( \frac{SOL_{us}(t_{1})}{SOL_{total}(t_{1})} \right)}{ \left( \frac{SOL_{us}(t_{1})}{SOL_{total}(t_{1})} \right) } \right)\\ +\end{aligned} +$$ + +Оскільки випуск інфляції лише збільшує загальну кількість токенів, а +нестейкінгована кількість залишається незмінною: + +$$ +\begin{aligned} + D_{us} &= \frac{1}{(1 + I_{1})} - 1\\ +\end{aligned} +$$ + +Отже: + +$$ +D_{us} = -\frac{I}{I + 1} +$$ + +### Оцінка Скоригованої Дохідності Стейкінгу + +Ми також можемо розрахувати _Скориговану Дохідність Стейкінгу_ $Y_{adj}$ як +зміну частки стейкінгованих токенів у пулі: + +$$ +Y_{adj} = \frac{P_s(t_2) - P_s(t_1)}{P_s(t_1)} +$$ + +Це спрощується до: + +$$ +Y_{adj} = \frac{ 1 + I(t)/P_s(t) }{ 1 + I(t) } - 1 +$$ + +### Відносна Дилюція + +Відношення $D_{us}/Y_{adj}$ дозволяє зрозуміти, наскільки сильніше +нестейкінговані токени піддаються дилюції у порівнянні зі стейкінгованими: + +$$ +\frac{D_{us}}{Y_{adj}} = \frac{ P_s }{ 1 - P_s } +$$ + +На основі цього видно, що збільшення частки стейкінгованих токенів значно +збільшує дилюцію нестейкінгованих токенів. Наприклад, якщо $80\%$ токенів мережі +стейкінговано, власник нестейкінгованих токенів зіткнеться з дилюцією у $400\%$ +більшою, ніж стейкінгований власник. + +Це підкреслює стимул для власників токенів до стейкінгу, щоб отримати +_Дохідність Стейкінгу_ та уникнути _Дилюції Нестейкінгованих Токенів_. diff --git a/docs/locales/uk/economics/inflation/inflation-schedule.md b/docs/locales/uk/economics/inflation/inflation-schedule.md new file mode 100644 index 000000000..dab4750e1 --- /dev/null +++ b/docs/locales/uk/economics/inflation/inflation-schedule.md @@ -0,0 +1,83 @@ +--- +sidebarLabel: Запропонований Графік Інфляції +title: Запропонований Графік Інфляції +altRoutes: + - /docs/uk/economics/inflation/inflation_schedule + - /docs/uk/intro/economics +--- + +Як було зазначено вище, _Графік Інфляції_ мережі унікально описується трьома +параметрами: _Початкова Ставка Інфляції_, _Ставка Дезінфляції_ та _Довгострокова +Ставка Інфляції_. При розгляді цих значень слід враховувати багато факторів: + +- Значна частина SOL, випущених через інфляцію, буде розподілена між власниками + стейкінгу пропорційно до кількості стейкінгованих SOL. Ми хочемо переконатися, + що дизайн _Графіку Інфляції_ забезпечує розумну _Дохідність Стейкінгу_ для + власників токенів, які делегують SOL, та провайдерів послуг валідації (через + комісії, які беруться з _Дохідності Стейкінгу_). +- Основний драйвер _Дохідності Стейкінгу_ — це кількість SOL у стейкінгу, + поділена на загальну кількість SOL (% від загальної кількості SOL у + стейкінгу). Таким чином, розподіл і делегування токенів серед валідаторів є + важливими факторами при визначенні початкових параметрів інфляції. +- Обмеження дохідності — це поточна область досліджень, яка може вплинути на + _Дохідність Стейкінгу_. Це не враховано у цій дискусії чи в моделюванні нижче. +- Загальний випуск токенів — тобто якою ми очікуємо _Поточну Загальну + Пропозицію_ через 10 чи 20 років? +- Довгострокова, стабільна інфляція є важливим фактором не тільки для сталого + підтримання екосистеми валідаторів і грантових програм Фонду Solana, але також + має бути налаштована з урахуванням очікуваних втрат і спалювання токенів з + часом. +- Темпи очікуваного зростання використання мережі як фактор для розгляду ставки + дезінфляції. З часом ми плануємо зниження інфляції та очікуємо зростання + використання. + +Виходячи з цих міркувань і обговорень у спільноті після початкового дизайну, +Фонд Solana пропонує наступні параметри _Графіку Інфляції_: + +- Початкова Ставка Інфляції: 8% +- Ставка Дезінфляції: -15% +- Довгострокова Ставка Інфляції: 1.5% + +Ці параметри визначають запропонований _Графік Інфляції_. Нижче показано +наслідки цих параметрів. Ці графіки лише показують вплив інфляційного випуску, +заданого _Графіком Інфляції_, як параметризовано вище. Вони _не враховують_ інші +фактори, які можуть вплинути на _Загальну Пропозицію_, такі як спалювання +комісій/рент, штрафи чи інші непередбачувані події знищення токенів у +майбутньому. Тому тут представлено **верхню межу** кількості SOL, випущених +через інфляцію. + +![Графік прикладу запропонованого графіку інфляції](/assets/docs/economics/proposed_inflation_schedule.png) + +На графіку вище показано відсоток річної ставки інфляції з часом, виходячи з +запропонованих параметрів інфляції. + +![Графік прикладу загальної пропозиції](/assets/docs/economics/proposed_total_supply.png) + +Подібним чином, тут показано _Поточну Загальну Пропозицію_ SOL [млн] з часом, за +умови початкової _Поточна Загальна Пропозиція_ `488,587,349 SOL` (тобто, у цьому +прикладі, взято _Поточну Загальну Пропозицію_ станом на `2020-01-25` і +моделюється інфляція, починаючи з цього дня). + +Відставляючи осторонь доступність валідаторів і комісії, очікувані показники +_Дохідності Стейкінгу_ та _Скоригованої Дохідності Стейкінгу_ є в першу чергу +функцією % від загального SOL у стейкінгу. Тому ми можемо моделювати _Дохідність +Стейкінгу_, якщо введемо додатковий параметр _% Стейкінгованих SOL_: + + + +Цей параметр має бути оцінений, оскільки це динамічна властивість власників +токенів і стимулів стейкінгу. Значення _% Стейкінгованих SOL_, представлені тут, +варіюються від 60% до 90%, що, на нашу думку, охоплює ймовірний діапазон, який +ми очікуємо, базуючись на зворотному зв’язку від спільнот інвесторів і +валідаторів, а також спостереженнях на порівнянних протоколах Proof-of-Stake. + +![Графік прикладу дохідності стейкінгу](/assets/docs/economics/example_staked_yields.png) + +На графіку вище показано приклад _Дохідності Стейкінгу_, яку може очікувати +учасник стейкінгу з часом у мережі Solana з вказаним _Графіком Інфляції_. Це +ідеалізована _Дохідність Стейкінгу_, оскільки вона не враховує вплив доступності +валідаторів на винагороди, комісії валідаторів, можливе обмеження дохідності та +можливі інциденти зі штрафами. Вона також ігнорує, що _% Стейкінгованих SOL_ є +динамічним за своєю суттю — економічні стимули, створені цим _Графіком +Інфляції_, стають більш зрозумілими, коли враховується _Дилюція Токенів_ (див. +розділ **Скоригована Дохідність Стейкінгу** нижче). diff --git a/docs/locales/uk/economics/inflation/terminology.md b/docs/locales/uk/economics/inflation/terminology.md new file mode 100644 index 000000000..23debb50c --- /dev/null +++ b/docs/locales/uk/economics/inflation/terminology.md @@ -0,0 +1,88 @@ +--- +sidebarLabel: Терміни, Пов’язані з Інфляцією +title: Терміни, Пов’язані з Інфляцією +--- + +При обговоренні інфляції та пов’язаних компонентів (наприклад, +винагород/дохідності/відсотків) використовується багато термінів. Тут ми +намагаємося визначити та уточнити деякі загальновживані поняття: + +### Поточна Загальна Пропозиція [SOL] + +Загальна кількість токенів (заблокованих або незаблокованих), які були створені +(через генезисний блок або інфляцію протоколу) мінус будь-які токени, які були +спалені (через комісії за транзакції або інші механізми) чи списані. Під час +запуску мережі було створено 500,000,000 SOL у генезисному блоці. З того часу +Поточна Загальна Пропозиція зменшилася через спалювання комісій за транзакції та +заплановану подію зменшення кількості токенів. _Поточну Загальну Пропозицію_ +Solana можна знайти за адресою: https://explorer.solana.com/supply + +### Ставка Інфляції [%] + +Протокол Solana автоматично створює нові токени за заздалегідь визначеним +графіком інфляції (обговорено нижче). _Ставка Інфляції [%]_ — це річний темп +зростання _Поточна Загальна Пропозиція_ на будь-який момент часу. + +### Графік Інфляції + +Детерміноване описання випуску токенів з часом. Фонд Solana пропонує +дезінфляційний _Графік Інфляції_. Тобто інфляція починається з найвищого +значення, а її темп зменшується з часом, доки не стабілізується на заздалегідь +визначеному довгостроковому рівні (див. обговорення нижче). Цей графік повністю +та унікально параметризується трьома числами: + +- **Початкова Ставка Інфляції [%]**: Початкова _Ставка Інфляції_ для моменту + активації інфляції. Темп випуску токенів може тільки знижуватися з цього + моменту. +- **Ставка Дезінфляції [%]**: Темп, з яким зменшується _Ставка Інфляції_. +- **Довгострокова Ставка Інфляції [%]**: Стабільна, довгострокова _Ставка + Інфляції_. + +### Ефективна Ставка Інфляції [%] + +Фактична ставка інфляції, що спостерігається в мережі Solana, після врахування +інших факторів, які можуть зменшити _Поточну Загальну Пропозицію_. Зазначимо, що +створення токенів поза описаним _Графіком Інфляції_ неможливе. + +- Хоча _Графік Інфляції_ визначає, як протокол випускає SOL, він не враховує + одночасного знищення токенів через різні фактори. Основний механізм спалювання + токенів — це спалювання частини кожної комісії за транзакцію. 50% кожної + комісії за транзакцію спалюється, решта залишається валідатору, який обробив + транзакцію. +- Додаткові фактори, такі як втрата приватних ключів і списання токенів, також + слід враховувати в комплексному аналізі _Ефективної Ставки Інфляції_. + Наприклад, оцінюється, що 10–20% всіх BTC втрачені та недоступні, і мережі + можуть зазнавати подібних щорічних втрат на рівні 1–2%. + +### Дохідність Стейкінгу [%] + +Темп повернення (також відомий як _відсоток_), який отримується за SOL, +поставлені на стейкінг у мережі. Зазвичай він зазначається як річний темп +(наприклад, "дохідність стейкінгу в мережі наразі становить 10% на рік"). + +- _Дохідність стейкінгу_ дуже цікавить валідаторів і власників токенів, які + бажають делегувати свої токени, щоб уникнути розмивання токенів через інфляцію + (масштаб якої обговорено нижче). +- 100% інфляційних випусків розподіляються між власниками стейкінгованих токенів + пропорційно до їхнього стейкінгованого SOL, а також валідаторами, які стягують + комісію з винагороди, отриманої за делегований SOL. + - Може бути враховано майбутнє розділення інфляційних випусків із введенням + _Архіваторів_ у економіку. _Архіватори_ — це учасники мережі, які надають + децентралізовані послуги зберігання, і їх також слід стимулювати розподілом + токенів з інфляційних випусків за цю послугу. +- _Дохідність Стейкінгу_ можна розрахувати за _Графіком Інфляції_ разом із + часткою _Поточна Загальна Пропозиція_, що перебуває в стейкінгу. + +### Дилюція Токенів [%] + +Розмивання визначається тут як зміна пропорційного представлення набору токенів +у більшому наборі через введення нових токенів. У практичному сенсі ми +обговорюємо розмивання стейкінгованих або нестейкінгованих токенів через +введення та розподіл інфляційних випусків по мережі. + +### Скоригована Дохідність Стейкінгу [%] + +Повна оцінка потенціалу заробітку від стейкінгу токенів повинна враховувати +стейкінговану _Дилюцію Токенів_ та її вплив на _Дохідність Стейкінгу_. Для цього +ми визначаємо _Скориговану Дохідність Стейкінгу_ як зміну фракційної власності +токенів у стейкінгу через розподіл інфляційних випусків. diff --git a/docs/locales/uk/economics/staking/index.md b/docs/locales/uk/economics/staking/index.md new file mode 100644 index 000000000..7f9a56564 --- /dev/null +++ b/docs/locales/uk/economics/staking/index.md @@ -0,0 +1,99 @@ +--- +sidebarLabel: Стейкінг +title: Стейкінг у Solana +--- + +_Примітка перед читанням: Усі згадки про збільшення значень стосуються +абсолютних показників балансу SOL. Цей документ не містить жодних припущень щодо +грошової вартості SOL у будь-який час._ + +Стейкуючи ваші токени SOL, ви допомагаєте забезпечувати безпеку мережі та +[отримувати винагороди](https://docs.anza.xyz/implemented-proposals/staking-rewards) +у процесі цього. + +Ви можете здійснювати стейкінг, делегуючи ваші токени валідаторам, які +обробляють транзакції та забезпечують роботу мережі. + +Делегування стейкінгу — це фінансова модель з розподіленим ризиком і +винагородою, яка може забезпечити дохід для власників токенів, делегованих на +тривалий період. Це досягається шляхом узгодження фінансових інтересів власників +токенів (делегаторів) та валідаторів, яким вони делегують токени. + +Чим більше стейку делеговано валідатору, тим частіше цей валідатор обирається +для запису нових транзакцій до реєстру. Чим більше транзакцій записує валідатор, +тим більше винагород отримують валідатор і його делегатори. Валідатори, які +налаштовують свої системи для обробки більшої кількості транзакцій, заробляють +пропорційно більше винагород і допомагають підтримувати мережу якомога швидшою +та стабільнішою. + +Валідатори несуть витрати на обслуговування та підтримку своїх систем, і ці +витрати передаються делегаторам у формі комісії, яка стягується як відсоток від +зароблених винагород. Ця комісія називається _комісією валідатора_. Оскільки +валідатори отримують більше винагород за більше делегованого стейку, вони можуть +конкурувати між собою, пропонуючи найнижчу комісію за свої послуги. + +Хоча це не реалізовано в протоколі Solana сьогодні, у майбутньому делегатори +можуть ризикувати втратити токени через процес, відомий як _слешинг_. Слешинг +передбачає вилучення та знищення частини SOL валідатора у відповідь на навмисну +зловмисну поведінку, наприклад, створення недійсних транзакцій або цензурування +певних типів транзакцій чи учасників мережі. + +На даний момент у протоколі Solana немає реалізації слешингу. Для отримання +додаткової інформації про слешинг перегляньте +[дорожню карту слешингу](https://docs.anza.xyz/proposals/optimistic-confirmation-and-slashing#slashing-roadmap). + +## Як здійснити стейкінг моїх токенів SOL? + +Ви можете здійснити стейкінг SOL, перемістивши свої токени в гаманець, який +підтримує стейкінг. Гаманець надасть інструкції для створення облікового запису +стейкінгу та делегування. + +#### Підтримувані Гаманці + +Багато веб- та мобільних гаманців підтримують операції стейкінгу Solana. Будь +ласка, перевірте статус підтримки у розробників вашого улюбленого гаманця. + +#### Інструменти командного рядка Solana + +- Інструменти командного рядка Solana дозволяють виконувати всі операції + стейкінгу в поєднанні з гаманцем у вигляді файлу ключів, паперовим гаманцем + або підключеним Ledger Nano. + [Команди для стейкінгу за допомогою інструментів командного рядка Solana](https://docs.anza.xyz/cli/examples/delegate-stake). + +#### Створення Облікового Запису Стейкінгу + +Виконуйте інструкції гаманця для створення облікового запису стейкінгу. Цей +обліковий запис відрізняється від облікових записів, які використовуються для +відправлення та отримання токенів. + +#### Вибір Валідатора + +Дотримуйтесь інструкцій гаманця для вибору валідатора. Ви можете отримати +інформацію про потенційно ефективних валідаторів за посиланнями нижче. Фонд +Solana не рекомендує конкретних валідаторів. + +Сайт solanabeach.io створений і підтримується одним з наших валідаторів, Staking +Facilities. Він надає графічну інформацію про мережу в цілому, а також список +кожного валідатора з деякими останніми статистиками їхньої продуктивності. + +- https://solanabeach.io + +Для перегляду статистики виробництва блоків використовуйте інструменти +командного рядка Solana: + +- `solana validators` +- `solana block-production` + +Команда Solana не надає рекомендацій щодо інтерпретації цієї інформації. +Виконуйте власне дослідження. + +#### Делегування Стейку + +Виконуйте інструкції гаманця для делегування вашого стейку обраному вами +валідатору. + +## Деталі Облікового Запису Стейкінгу + +Для отримання додаткової інформації про операції та дозволи, пов’язані з +обліковим записом стейкінгу, дивіться +[Облікові Записи Стейкінгу](/docs/uk/economics/staking/stake-accounts.md) diff --git a/docs/locales/uk/economics/staking/stake-accounts.md b/docs/locales/uk/economics/staking/stake-accounts.md new file mode 100644 index 000000000..683a6d5a2 --- /dev/null +++ b/docs/locales/uk/economics/staking/stake-accounts.md @@ -0,0 +1,87 @@ +--- +sidebarLabel: Облікові Записи Стейкінгу +title: Облікові Записи Стейкінгу +--- + +Обліковий запис стейкінгу на Solana може використовуватися для делегування +токенів валідаторам у мережі з можливістю отримання винагород для власника +облікового запису стейкінгу. Облікові записи стейкінгу створюються та керуються +інакше, ніж традиційні адреси гаманців, відомі як _системні облікові записи_. +Системний обліковий запис здатний лише надсилати та отримувати SOL від інших +облікових записів у мережі, тоді як обліковий запис стейкінгу підтримує +складніші операції, необхідні для управління делегуванням токенів. + +Облікові записи стейкінгу на Solana також працюють інакше, ніж у інших +блокчейн-мережах Proof-of-Stake, з якими ви могли бути знайомі. У цьому +документі описується загальна структура та функції облікового запису стейкінгу +Solana. + +#### Адреса Облікового Запису + +Кожен обліковий запис стейкінгу має унікальну адресу, яка може використовуватися +для перегляду інформації про обліковий запис через командний рядок або будь-які +інструменти дослідження мережі. Однак, на відміну від адреси гаманця, власник +ключової пари адреси не обов'язково має контроль над обліковим записом. +Насправді, для адреси облікового запису стейкінгу може навіть не існувати +ключова пара чи приватний ключ. + +Ключова пара створюється лише під час +[створення облікового запису стейкінгу за допомогою інструментів командного рядка](https://docs.anza.xyz/cli/examples/delegate-stake#create-a-stake-account). +Нова ключова пара створюється виключно для забезпечення унікальності адреси +облікового запису стейкінгу. + +#### Розуміння Авторитетів Облікового Запису + +Деякі типи облікових записів можуть мати один або більше _авторитетів підпису_, +пов’язаних з обліковим записом. Авторитет облікового запису використовується для +підпису певних транзакцій для облікового запису, яким він керує. Це +відрізняється від інших блокчейнів, де власник ключової пари контролює всі дії +облікового запису. + +Кожен обліковий запис стейкінгу має два авторитети підпису, які вказані їхніми +відповідними адресами: + +- _Авторитет стейкінгу_ використовується для підпису транзакцій, пов’язаних із: + + - Делегуванням стейку + - Деактивацією делегування стейку + - Розділенням облікового запису на два окремі + - Об'єднанням двох облікових записів стейкінгу + - Призначенням нового авторитету стейкінгу + +- _Авторитет виведення_ підписує транзакції для: + - Виведення неделегованого стейку + - Призначення нового авторитету виведення + - Призначення нового авторитету стейкінгу + +#### Множинне Делегування + +Один обліковий запис стейкінгу може бути делегований лише одному валідатору. Усі +токени в обліковому записі є або делегованими, або неделегованими. Щоб +делегувати частину токенів кільком валідаторам, потрібно створити кілька +облікових записів стейкінгу. + +#### Об'єднання Облікових Записів + +Два облікові записи стейкінгу з однаковими авторитетами та параметрами +блокування можуть бути об’єднані в один. + +#### Розігрів та Охолодження Делегування + +Процес делегування або деактивації делегування не є миттєвим і може займати +кілька [епох](/docs/terminology.md#epoch). + +#### Блокування + +Облікові записи стейкінгу можуть мати блокування, яке забороняє виведення +токенів до досягнення певної дати або епохи. + +#### Видалення Облікового Запису + +Обліковий запис стейкінгу, баланс якого дорівнює 0 SOL, автоматично припиняє +існувати. + +#### Перегляд Облікових Записів Стейкінгу + +Інформацію про обліковий запис стейкінгу можна переглянути через +[Solana Explorer](http://explorer.solana.com/accounts). diff --git a/docs/locales/uk/economics/staking/stake-programming.md b/docs/locales/uk/economics/staking/stake-programming.md new file mode 100644 index 000000000..ce5511476 --- /dev/null +++ b/docs/locales/uk/economics/staking/stake-programming.md @@ -0,0 +1,31 @@ +--- +title: Програмування Стейкінгу +--- + +Для максимізації розподілу стейку, децентралізації та стійкості до цензури в +мережі Solana, стейкінг може виконуватись програмно. Команда та спільнота +розробили кілька програм для роботи як на ланцюгу, так і поза ним, щоб зробити +управління стейками простішим. + +#### Stake-o-matic, також відомий як боти автоделегування + +Ця позаланцюгова програма управляє великою кількістю валідаторів, яким делегує +стейк центральний орган. Фонд Solana використовує бота автоделегування для +регулярного делегування свого стейку "неспійманим" валідаторам, які відповідають +визначеним вимогам продуктивності. + +#### Stake Pools + +Ця програма на ланцюгу об'єднує SOL для стейкінгу, яким управляє менеджер, +дозволяючи власникам SOL здійснювати стейкінг та отримувати винагороди без +необхідності управляти стейками. Користувачі депонують SOL в обмін на SPL-токени +(похідні стейкінгу), які представляють їхню частку в пулі стейкінгу. Менеджер +пулу здійснює стейкінг внесених SOL відповідно до своєї стратегії, можливо, +використовуючи варіант бота автоделегування, описаного вище. Коли стейки +отримують винагороди, вартість пулу та токенів пулу пропорційно зростає. +Нарешті, власники токенів пулу можуть повернути SPL-токени назад у пул стейкінгу +для викупу SOL, тим самим беручи участь у децентралізації з мінімальними +зусиллями. + +Детальнішу інформацію можна знайти в +[документації SPL Stake Pool](https://spl.solana.com/stake-pool). diff --git a/docs/locales/uk/index.md b/docs/locales/uk/index.md new file mode 100644 index 000000000..94f35a425 --- /dev/null +++ b/docs/locales/uk/index.md @@ -0,0 +1,105 @@ +--- +sidebarSortOrder: 0 +title: Документація Solana +seoTitle: Дізнайтеся, як працює блокчейн Solana +description: + "Solana — це високопродуктивний блокчейн, створений для масового впровадження. + Дізнайтеся, чому Solana є найкращим вибором для розробників, які прагнуть + створювати масштабовані блокчейн-додатки." +altRoutes: + - /docs/intro/history + - /docs/intro + - /docs/intro/overview +isHiddenInNavSidebar: true +--- + +Solana — це блокчейн, створений для масового використання. Це високопродуктивна +мережа, яка використовується для різних сфер, включаючи фінанси, NFT, платежі та +ігри. Solana працює як єдина глобальна станова машина, є відкритою, +інтероперабельною та децентралізованою. + +## Початок роботи + +Пориньте у світ Solana, щоб почати створювати або налаштовувати своє локальне +середовище. + +- [Швидкий старт](/docs/intro/quick-start) — Створіть і розгорніть свою першу + програму на Solana прямо у браузері за допомогою Solana Playground +- [Налаштування локального середовища](/docs/intro/installation) — Встановіть + CLI Solana для налаштування локального середовища розробки + +## Почніть навчання + +Поглиблено вивчіть основні концепції, які роблять Solana унікальною серед інших +блокчейнів. + +- [Акаунти](/docs/core/accounts) — Механізм зберігання даних і стану для Solana +- [Комісії в Solana](/docs/core/fees) — Різні витрати, пов’язані з використанням + мережі +- [Транзакції](/docs/core/transactions) — Набір інструкцій для виконання + блокчейном +- [Програми](/docs/core/programs) — Виконуваний код для виконання дій у + блокчейні +- [Програмно похідні адреси](/docs/core/pda) — Детерміновано створені адреси, + які дозволяють програмам Solana програмно "підписувати" транзакції +- [Виклики між програмами](/docs/core/cpi) — Основний механізм "композованості" + Solana, який дозволяє програмам "викликати" одна одну + +## Розуміння архітектури + +Дізнайтеся, як працює блокчейн Proof-of-Stake у основі Solana. + +- [Валідатори](https://docs.anza.xyz/validator/anatomy) — окремі вузли, які є + основою мережі +- [Кластери](/docs/core/clusters) — група валідаторів, що працюють разом для + досягнення консенсусу + +## Запуск валідатора + +Дізнайтеся, що потрібно для роботи валідатора Solana та забезпечення безпеки +мережі. + +- [Системні вимоги](https://docs.anza.xyz/operations/requirements) — + Рекомендовані апаратні вимоги та очікувана кількість SOL, необхідна для + запуску валідатора +- [Швидкий старт](https://docs.anza.xyz/operations/setup-a-validator) — + Налаштуйте валідатор і підключіться до кластера вперше + +## Чому Solana? + +Створена для масштабування, Solana призначена для того, щоб блокчейн-додатки +могли досягати мільйонів користувачів. Замість оптимізації під блокчейн-рівень +розробники можуть зосередитися на створенні додатків, які досягнуть +відповідності ринку. Мережа не тільки може масштабуватися для поточних потреб +блокчейн-додатків, але й постійно оптимізується з урахуванням досвіду +користувачів. + +Створення найкращого користувацького досвіду є головним пріоритетом для +розробників. У блокчейнах користувацький досвід часто обмежений базовими +технологіями, що спричиняє повільний час відгуку та високі комісії. Низькі +комісії Solana та час підтвердження в 400 мс дозволяють розробникам створювати +зручні для користувачів додатки, доступні кожному. + +## Особливості Solana + +| Функція | Опис | +| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Розробка програм на блокчейні | Можливість розробляти та розгортати програми на блокчейні. Користувачі можуть взаємодіяти з цими програмами без дозволу, усуваючи потребу у посередниках для створення додатків. | +| 400 мс для блоків | Кожна транзакція користувачів у Solana підтверджується в блоці. З цільовим часом 400 мс для кожного блоку, взаємодія користувачів є швидкою, забезпечуючи найкращий у своєму класі досвід. | +| Низькі комісії | Комісії в Solana відомі своєю низькістю. Середня комісія становить 0.00064 SOL за транзакцію, що дозволяє створювати додатки для користувачів з усього світу, незалежно від їх походження. | +| Висока пропускна здатність | Масштабування до тисяч транзакцій за секунду, Solana створена для масштабування відповідно до потреб користувачів вашого додатку. | + +## Як користуватися цими документами + +Зліва ви знайдете бічну панель документації. Вона містить документацію у порядку +від базової до більш просунутої інформації. Якщо ви новачок у Solana, +рекомендуємо почати з самого верху і рухатися вниз. Однак ви можете читати їх у +будь-якому порядку, який вам подобається. + +Коли будете готові почати створення, ознайомтеся з посібником +[Швидкий старт](/docs/intro/quick-start). + +## Потрібна допомога? + +Отримайте допомогу від спільноти Solana на +[Solana StackExchange](https://solana.stackexchange.com). diff --git a/docs/locales/uk/intro/dev.md b/docs/locales/uk/intro/dev.md new file mode 100644 index 000000000..725c8aeb0 --- /dev/null +++ b/docs/locales/uk/intro/dev.md @@ -0,0 +1,197 @@ +--- +sidebarLabel: Вступ до Розробки +title: "Початок Розробки на Solana" +description: "Дізнайтеся, як почати розробляти на Solana" +sidebarSortOrder: 2 +keywords: + - основи solana + - посібник + - вступ до розробки solana + - розробник блокчейну + - розробник web3 +--- + +Ласкаво просимо до документації для розробників Solana! + +На цій сторінці зібрано все, що вам потрібно знати для початку розробки на +Solana, включаючи основні вимоги, принципи роботи та інструменти, необхідні для +старту. + +## Огляд Розробки на Високому Рівні + +Розробку на Solana можна розділити на дві основні частини: + +1. **Розробка Програм на Блокчейні**: Тут ви створюєте та розгортаєте + користувацькі програми безпосередньо у блокчейні. Після розгортання будь-хто, + хто знає, як із ними працювати, може їх використовувати. Ці програми можна + писати на Rust, C або C++. Rust наразі має найбільшу підтримку для розробки + програм на блокчейні. +2. **Клієнтська Розробка**: Це створення програмного забезпечення + (децентралізованих додатків або dApps), яке взаємодіє з програмами на + блокчейні. Ваші додатки можуть надсилати транзакції для виконання дій у + блокчейні. Клієнтську розробку можна виконувати на будь-якій мові + програмування. + +"Зв'язок" між клієнтською та блокчейн-частиною забезпечується +[Solana JSON RPC API](https://solana.com/docs/rpc). Клієнтська частина надсилає +запити RPC до мережі Solana для взаємодії з програмами на блокчейні. Це дуже +схоже на звичайний процес розробки між frontend і backend. Головна відмінність у +роботі з Solana — це те, що backend є глобальним блокчейном без дозволів. Це +означає, що будь-хто може взаємодіяти з вашою програмою на блокчейні без +необхідності видачі API-ключів або будь-яких інших форм дозволів. + +![Як клієнти працюють із блокчейном Solana](/assets/docs/intro/developer_flow.png) + +Розробка на Solana відрізняється від інших блокчейнів завдяки своїм +високо-композитним програмам на блокчейні. Це означає, що ви можете будувати на +базі вже існуючих програм, часто без необхідності створення власних. Наприклад, +якщо ви хочете працювати з токенами, ви можете використовувати +[Token Program](/docs/uk/core/tokens.md), який вже розгорнутий у мережі. Уся +розробка вашого додатка буде клієнтською, на обраній вами мові програмування. + +Розробники, які хочуть будувати на Solana, знайдуть, що стек розробки дуже +схожий на інші. Основна відмінність у тому, що ви працюєте з блокчейном і +повинні враховувати, як користувачі взаємодіють із вашим додатком на блокчейні, +а не тільки у frontend. Розробка на Solana все ще включає CI/CD, тестування, +інструменти для налагодження, frontend і backend, як і будь-який звичайний +процес розробки. + +## Що Вам Потрібно для Початку + +Для початку розробки на Solana вам знадобляться різні інструменти залежно від +того, чи ви розробляєте клієнтські додатки, програми на блокчейні або обидва. + +### Клієнтська Розробка + +Якщо ви розробляєте програми на блокчейні, вам потрібно знати Rust. + +Якщо ж ви розробляєте клієнтські додатки, ви можете працювати на будь-якій мові +програмування, з якою вам зручно. Solana має SDK, створені спільнотою, щоб +допомогти розробникам взаємодіяти з мережею Solana на більшості популярних мов: + +| Мова | SDK | +| ---------- | -------------------------------------------------------------------------------------------------------- | +| RUST | [solana_sdk](https://docs.rs/solana-sdk/latest/solana_sdk/) | +| Typescript | [@solana/web3.js](https://github.com/solana-labs/solana-web3.js) | +| Python | [solders](https://github.com/kevinheavey/solders) | +| Java | [solanaj](https://github.com/skynetcap/solanaj) or [solana4j](https://github.com/LMAX-Exchange/solana4j) | +| C++ | [solcpp](https://github.com/mschneider/solcpp) | +| Go | [solana-go](https://github.com/gagliardetto/solana-go) | +| Kotlin | [solanaKT](https://github.com/metaplex-foundation/SolanaKT) or [sol4k](https://github.com/sol4k/sol4k) | +| Dart | [solana](https://github.com/espresso-cash/espresso-cash-public/tree/master/packages/solana) | +| C# | [solnet](https://github.com/bmresearch/Solnet) | +| GdScript | [godot](https://github.com/Virus-Axel/godot-solana-sdk/) | + +Вам також знадобиться підключення до RPC для взаємодії з мережею. Ви можете +скористатися [провайдером RPC](https://solana.com/rpc) або +[запустити власний RPC-вузол](https://docs.anza.xyz/operations/setup-an-rpc-node). + +Щоб швидко розпочати роботу з фронтендом для вашого додатка, ви можете +згенерувати налаштовуваний каркас Solana, ввівши наступну команду у ваш CLI: + +```bash +npx create-solana-dapp +``` + +Ця команда створить новий проєкт із усіма необхідними файлами та базовою +конфігурацією для початку розробки на Solana. Каркас включатиме як приклад +фронтенда, так і шаблон програми на блокчейні (якщо ви його обрали). Ви можете +ознайомитися з +[документацією `create-solana-dapp`](https://github.com/solana-developers/create-solana-dapp?tab=readme-ov-file#create-solana-dapp), +щоб дізнатися більше. + +### Розробка Програм на Блокчейні + +Розробка програм на блокчейні включає написання програм на Rust, C або C++. +Спочатку переконайтеся, що у вас встановлений Rust. Ви можете зробити це за +допомогою наступної команди: + +```bash +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +``` + +Вам також потрібно встановити [Solana CLI](/docs/uk/intro/installation.md), щоб +компілювати та розгортати ваші програми. Ви можете встановити Solana CLI, +виконавши наступну команду: + +```bash +sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)" +``` + +Використовуючи Solana CLI, рекомендується запускати локальний валідатор для +тестування вашої програми. Щоб запустити локальний валідатор після встановлення +Solana CLI, виконайте наступну команду: + +```bash +solana-test-validator +``` + +Це запустить локальний валідатор на вашій машині, який ви можете використовувати +для тестування ваших програм. Ви можете +[докладніше прочитати про локальну розробку в цьому посібнику](/docs/uk/intro/installation.md). + +Під час розробки програм на блокчейні ви можете вибрати між написанням програм +на чистому Rust (без фреймворку) або використанням фреймворку Anchor. Anchor +спрощує розробку на Solana, надаючи високорівневий API для розробників. +Подумайте про Anchor як про використання React для створення вебсайтів замість +чистого Javascript і HTML. Хоча Javascript і HTML дають вам більше контролю, +React прискорює розробку та робить її простішою. Докладніше про +[Anchor](https://www.anchor-lang.com/) можна дізнатися на їхньому сайті. + +Вам знадобиться спосіб тестування вашої програми. Ось кілька способів тестування +залежно від ваших уподобань щодо мови програмування: + +- [solana-program-test](https://docs.rs/solana-program-test/latest/solana_program_test/) + — фреймворк для тестування, написаний на Rust. +- [solana-bankrun](https://kevinheavey.github.io/solana-bankrun/) — фреймворк + для тестування, написаний для тестів на Typescript. +- [bankrun](https://kevinheavey.github.io/solders/tutorials/bankrun.html) — + фреймворк для тестування, написаний для тестів на Python. + +Якщо ви не хочете розробляти програми локально, існує також +[онлайн IDE Solana Playground](https://beta.solpg.io). Solana Playground +дозволяє писати, тестувати та розгортати програми на Solana. Ви можете розпочати +роботу з Solana Playground, +[слідувавши нашому посібнику швидкого старту](/docs/uk/intro/quick-start). + +### Середовища Розробки + +Вибір правильного середовища залежно від вашої роботи дуже важливий. У Solana є +кілька середовищ (кластерів) для забезпечення якісного тестування та CI/CD +практик: + +- **Mainnet Beta**: Продуктивна мережа, де відбувається вся дія. Транзакції тут + коштують реальних грошей. +- **Devnet**: Мережа для забезпечення якості, де ви розгортаєте ваші програми + для тестування перед розгортанням у продуктивне середовище. Це як "середовище + для постановки". +- **Local**: Локальна мережа, яку ви запускаєте на своїй машині за допомогою + `solana-test-validator` для тестування ваших програм. Це має бути вашим першим + вибором під час розробки. + +## Побудова на Основі Прикладів + +Під час початку розробки на Solana є кілька ресурсів, які допоможуть прискорити +ваш шлях: + +- [Solana Cookbook](https://solana.com/developers/cookbook): Збірка довідників і + фрагментів коду для допомоги у розробці на Solana. +- [Приклади Програм Solana](https://github.com/solana-developers/program-examples): + Репозиторій прикладів програм, що надають будівельні блоки для різних дій у + ваших програмах. +- [Посібники](https://solana.com/developers/guides): Посібники та інструкції, + які проведуть вас через процес розробки на Solana. + +## Отримання Підтримки + +Найкращу підтримку ви можете знайти на +[Solana StackExchange](https://solana.stackexchange.com/). Спочатку пошукайте +своє питання там — є велика ймовірність, що вже існує схоже питання з +відповіддю. Якщо його там немає, додайте нове питання! Не забудьте включити +якомога більше деталей у ваше питання, і, будь ласка, використовуйте текст (а не +скріншоти) для відображення повідомлень про помилки, щоб інші люди з такою ж +проблемою могли знайти ваше питання! + +## Наступні кроки + +[Тепер ви готові почати створювати на Solana!](/docs/uk/intro/quick-start) diff --git a/docs/locales/uk/intro/index.md b/docs/locales/uk/intro/index.md new file mode 100644 index 000000000..8b9684de4 --- /dev/null +++ b/docs/locales/uk/intro/index.md @@ -0,0 +1,5 @@ +--- +title: Getting Started +sidebarSortOrder: 1 +metaOnly: true +--- diff --git a/docs/locales/uk/intro/installation.md b/docs/locales/uk/intro/installation.md new file mode 100644 index 000000000..117c101dd --- /dev/null +++ b/docs/locales/uk/intro/installation.md @@ -0,0 +1,674 @@ +--- +title: Installation +seoTitle: Install the Solana CLI and Anchor +sidebarSortOrder: 1 +description: + Покроковий посібник з налаштування локального середовища розробки для Solana. + Дізнайтеся, як встановити Rust, Solana CLI та Anchor Framework на Windows + (WSL), Linux і Mac. Включає інструкції зі створення гаманців, запиту airdrop і + запуску локального валідатора. +altRoutes: + - /developers/guides/getstarted/setup-local-development + - /docs/uk/install + - /install + - /setup +--- + +Цей розділ охоплює етапи налаштування локального середовища для розробки на +Solana. + +## Встановлення Залежностей + +- Користувачі Windows повинні спочатку встановити WSL (Windows Subsystem for + Linux), а потім встановити залежності, зазначені в розділі Linux нижче. +- Користувачі Linux повинні спочатку встановити залежності, зазначені в розділі + Linux нижче. +- Користувачі Mac повинні почати з інструкцій з установки Rust нижче. + + + + +Для розробки програм Solana на Windows **необхідно використовувати +[WSL](https://learn.microsoft.com/en-us/windows/wsl/install)** (Windows +Subsystem for Linux). Усі додаткові залежності необхідно встановлювати через +термінал Linux. + +Після встановлення WSL встановіть залежності, зазначені в розділі Linux нижче, +перш ніж переходити до установки Rust, Solana CLI та Anchor CLI. + +Щоб встановити WSL, виконайте наступну команду у Windows PowerShell: + +```shell +wsl --install +``` + +Процес встановлення запропонує вам створити обліковий запис користувача за +замовчуванням. + +![WSL Install](/assets/docs/intro/installation/wsl-install.png) + +За замовчуванням WSL встановлює Ubuntu. Ви можете відкрити термінал Linux, +ввівши "Ubuntu" у пошуковому рядку. + +![WSL Ubuntu](/assets/docs/intro/installation/wsl-ubuntu-search.png) + +Якщо ваш термінал Ubuntu виглядає так, як на зображенні нижче, ви можете +зіткнутися з проблемою, коли комбінація `ctrl + v` (вставити) не працює у +терміналі. + +![Ubuntu Terminal](/assets/docs/intro/installation/wsl-ubuntu-terminal-1.png) + +Якщо виникла ця проблема, відкрийте Windows Terminal, ввівши "Terminal" у +пошуковому рядку. + +![Windows Terminal](/assets/docs/intro/installation/wsl-windows-terminal.png) + +Далі закрийте Windows Terminal і знову відкрийте термінал Linux, ввівши "Ubuntu" +у пошуку. Тепер термінал має виглядати так, як на зображенні нижче, і комбінація +`ctrl + v` (вставити) має працювати. + +![Ubuntu Terminal](/assets/docs/intro/installation/wsl-ubuntu-terminal-2.png) + +Якщо ви використовуєте VS Code, розширення +[WSL extension](https://code.visualstudio.com/docs/remote/wsl-tutorial) дозволяє +використовувати WSL та VS Code разом. + +![WSL Setup in VS Code](/assets/docs/intro/installation/wsl-vscode.png) + +У статусному рядку VS Code ви повинні побачити наступне: + +![WSL: Ubuntu](/assets/docs/intro/installation/wsl-vscode-ubuntu.png) + +Після налаштування WSL всі додаткові залежності потрібно встановлювати через +термінал Linux. Встановіть залежності, зазначені в розділі Linux нижче, перш ніж +переходити до встановлення Rust, Solana CLI та Anchor CLI. + + + + +Для встановлення Anchor CLI необхідно виконати наступні залежності. + +Спочатку виконайте наступну команду: + +```shell +sudo apt-get update +``` + +Далі встановіть наступні залежності: + +```shell +sudo apt-get install -y \ + build-essential \ + pkg-config \ + libudev-dev llvm libclang-dev \ + protobuf-compiler libssl-dev +``` + +Якщо під час встановлення `protobuf-compiler` ви зіткнетеся з такою помилкою, +спочатку переконайтеся, що виконали команду `sudo apt-get update`: + +``` +Package protobuf-compiler is not available, but is referred to by another package. +This may mean that the package is missing, has been obsoleted, or +is only available from another source +``` + + + + + + +### Встановлення Rust + +Програми Solana пишуться на +[мові програмування Rust](https://www.rust-lang.org/). + +Рекомендований метод встановлення Rust — це +[rustup](https://www.rust-lang.org/tools/install). + +Виконайте наступну команду для встановлення Rust: + +```shell +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y +``` + +Після завершення встановлення ви повинні побачити таке повідомлення: + + + + +``` +Rust is installed now. Great! + +To get started you may need to restart your current shell. +This would reload your PATH environment variable to include +Cargo's bin directory ($HOME/.cargo/bin). + +To configure your current shell, you need to source +the corresponding env file under $HOME/.cargo. + +This is usually done by running one of the following (note the leading DOT): +. "$HOME/.cargo/env" # For sh/bash/zsh/ash/dash/pdksh +source "$HOME/.cargo/env.fish" # For fish +``` + + + + +Виконайте наступну команду, щоб оновити змінну середовища PATH і включити +директорію `bin` Cargo: + +```shell +. "$HOME/.cargo/env" +``` + +Щоб перевірити, чи встановлення було успішним, перевірте версію Rust: + +```shell +rustc --version +``` + +Ви повинні побачити результат, схожий на наступний: + +``` +rustc 1.80.1 (3f5fd8dd4 2024-08-06) +``` + +### Встановлення Solana CLI + +Solana CLI надає всі необхідні інструменти для створення та розгортання програм +Solana. + +Встановіть набір інструментів Solana CLI за допомогою офіційної команди +встановлення: + +```shell +sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)" +``` + +Ви можете замінити `stable` на тег релізу, який відповідає версії програмного +забезпечення потрібного релізу (наприклад, `v2.0.3`), або використовувати один +із трьох символічних назв каналів: `stable`, `beta` або `edge`. + +Якщо ви встановлюєте Solana CLI вперше, ви можете побачити таке повідомлення із +запитом на додавання змінної середовища PATH: + +``` +Close and reopen your terminal to apply the PATH changes or run the following in your existing shell: + +export PATH="/Users/test/.local/share/solana/install/active_release/bin:$PATH" +``` + + + + +Якщо ви використовуєте термінал Linux або WSL, ви можете додати змінну +середовища PATH у файл конфігурації вашої оболонки, виконавши команду, зазначену +під час встановлення, або перезапустивши термінал. + +```shell +export PATH="$HOME/.local/share/solana/install/active_release/bin:$PATH" +``` + + + + +Якщо ви використовуєте Mac із оболонкою `zsh`, виконання стандартної команди +`export PATH`, зазначеної під час встановлення, не зберігається після закриття +термінала. + +Замість цього ви можете додати PATH у файл конфігурації оболонки, виконавши +наступну команду: + +```shell +echo 'export PATH="$HOME/.local/share/solana/install/active_release/bin:$PATH"' >> ~/.zshrc +``` + +Далі виконайте наступну команду, щоб оновити сесію термінала, або перезапустіть +термінал. + +```shell +source ~/.zshrc +``` + + + + +Щоб перевірити, чи встановлення було успішним, перевірте версію Solana CLI: + +```shell +solana --version +``` + +Ви повинні побачити результат, схожий на наступний: + +``` +solana-cli 1.18.22 (src:9efdd74b; feat:4215500110, client:Agave) +``` + +Ви можете переглянути всі доступні версії у +[репозиторії Agave на Github](https://github.com/anza-xyz/agave/releases). + + + +Agave — це клієнт валідатора від [Anza](https://www.anza.xyz/), раніше відомий +як клієнт валідатора Solana Labs. + + + +Щоб оновити Solana CLI до останньої версії, ви можете використати наступну +команду: + +```shell +agave-install update +``` + +### Встановлення Anchor CLI + +[Anchor](https://www.anchor-lang.com/) — це фреймворк для розробки програм на +Solana. Anchor використовує макроси Rust, щоб спростити процес написання програм +на Solana. + +Існує два способи встановлення Anchor CLI та інструментів: + +1. За допомогою Anchor Version Manager (AVM) — **рекомендований спосіб + встановлення**, оскільки він спрощує оновлення версій Anchor у майбутньому. +2. Без AVM — вимагає більш ручного процесу для оновлення версій Anchor у + майбутньому. + + + + +Менеджер версій Anchor (AVM) дозволяє встановлювати та керувати різними версіями +Anchor на вашій системі, включаючи зручне оновлення версій у майбутньому. + +Встановіть AVM за допомогою наступної команди: + +```shell +cargo install --git https://github.com/coral-xyz/anchor avm --force +``` + +Перевірте, щоб переконатися, що AVM було встановлено та він доступний: + +```shell +avm --version +``` + +Встановіть останню версію Anchor CLI за допомогою AVM: + +```shell +avm install latest +avm use latest +``` + +Або встановіть конкретну версію Anchor CLI, вказавши бажану версію: + +```shell +avm install 0.30.1 +avm use 0.30.1 +``` + +> Don't forget to run the `avm use` command to declare which Anchor CLI version +> should be used on your system. +> +> - If you installed the `latest` version, run `avm use latest`. +> - If you installed the version `0.30.1`, run `avm use 0.30.1`. + + + + + +Встановіть конкретну версію Anchor CLI за допомогою наступної команди: + +```shell +cargo install --git https://github.com/coral-xyz/anchor --tag v0.30.1 anchor-cli +``` + + + + +Під час встановлення ви можете побачити таке попередження. Однак це не впливає +на процес встановлення. + + + + +``` +warning: unexpected `cfg` condition name: `nightly` + --> cli/src/lib.rs:1:13 + | +1 | #![cfg_attr(nightly, feature(proc_macro_span))] + | ^^^^^^^ + | + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `docsrs`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows` + = help: consider using a Cargo feature instead + = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint: + [lints.rust] + unexpected_cfgs = { level = "warn", check-cfg = ['cfg(nightly)'] } + = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(nightly)");` to the top of the `build.rs` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: `anchor-cli` (lib) generated 1 warning +``` + + + + +Щоб перевірити, чи встановлення було успішним, перевірте версію Anchor CLI: + +```shell +anchor --version +``` + +Ви повинні побачити результат, схожий на наступний: + +``` +anchor-cli 0.30.1 +``` + +Під час встановлення Anchor CLI на Linux або WSL ви можете зіткнутися з такою +помилкою: + +``` +error: could not exec the linker cc = note: Permission denied (os error 13) +``` + +Якщо ви бачите це повідомлення про помилку, виконайте наступні кроки: + +1. Встановіть залежності, зазначені в розділі Linux на початку цієї сторінки. +2. Повторіть спробу встановлення Anchor CLI. + +#### Node.js та Yarn + +Node.js та Yarn необхідні для запуску тестового файлу (TypeScript), створеного +за допомогою команди `anchor init`. (Шаблон тестів на Rust також доступний за +допомогою `anchor init --test-template rust`) + + + + +Рекомендований спосіб встановлення Node — використання +[Node Version Manager (nvm)](https://github.com/nvm-sh/nvm). + +Встановіть nvm за допомогою наступної команди: + +```shell +curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash +``` + +Перезапустіть ваш термінал і перевірте, чи встановлено nvm: + +```shell +command -v nvm +``` + +Далі використовуйте `nvm`, щоб встановити Node.js: + +```shell +nvm install node +``` + +Щоб перевірити, чи встановлення було успішним, перевірте версію Node.js: + +``` +node --version +``` + +Ви повинні побачити результат, схожий на наступний: + +``` +v22.7.0 +``` + + + + +Встановіть Yarn: + +```shell +npm install --global yarn +``` + +Щоб перевірити, чи встановлення було успішним, перевірте версію Yarn: + +``` +yarn --version +``` + +Ви повинні побачити наступний результат: + +``` +1.22.1 +``` + + + + +Під час виконання команди `anchor build`, якщо ви стикаєтеся з такими помилками: + + + + +``` +error: not a directory: '.../solana-release/bin/sdk/sbf/dependencies/platform-tools/rust/lib' +``` + +Спробуйте ці рішення: + +1. Примусове встановлення за допомогою наступної команди: + +```shell +cargo build-sbf --force-tools-install +``` + +2. Якщо це не спрацювало, очистіть кеш Solana: + +```shell +rm -rf ~/.cache/solana/* +``` + + + + + +Ви можете виправити це, змінивши поле версії у файлі `Cargo.lock`: + +``` +version = 3 +``` + +Дивіться [це обговорення](https://github.com/coral-xyz/anchor/issues/3392) для +отримання додаткової інформації. + + + + + +Після застосування будь-якого з рішень спробуйте знову виконати команду +`anchor build`. + +Якщо ви використовуєте Linux або WSL і стикаєтеся з такими помилками під час +виконання команди `anchor test` після створення нового проєкту Anchor, це може +бути через відсутність Node.js або Yarn: + +``` +Permission denied (os error 13) +``` + +``` +No such file or directory (os error 2) +``` + + + +## Основи Solana CLI + +Цей розділ ознайомить вас із деякими поширеними командами Solana CLI для початку +роботи. + + + +### Конфігурація Solana + +Щоб переглянути вашу поточну конфігурацію: + +```shell +solana config get +``` + +Ви повинні побачити результат, схожий на наступний: + +``` +Config File: /Users/test/.config/solana/cli/config.yml +RPC URL: https://api.mainnet-beta.solana.com +WebSocket URL: wss://api.mainnet-beta.solana.com/ (computed) +Keypair Path: /Users/test/.config/solana/id.json +Commitment: confirmed +``` + +RPC URL та Websocket URL вказують кластер Solana, до якого CLI надсилатиме +запити. За замовчуванням це буде mainnet-beta. + +Ви можете оновити кластер Solana CLI за допомогою наступних команд: + +``` +solana config set --url mainnet-beta +solana config set --url devnet +solana config set --url localhost +solana config set --url testnet +``` + +Ви також можете використовувати наступні скорочені опції: + +``` +solana config set -um # For mainnet-beta +solana config set -ud # For devnet +solana config set -ul # For localhost +solana config set -ut # For testnet +``` + +Шлях до ключової пари (Keypair Path) вказує розташування гаманця за +замовчуванням, який використовується Solana CLI (для оплати комісій за +транзакції та розгортання програм). Шлях за замовчуванням: +`~/.config/solana/id.json`. У наступному кроці описано, як створити ключову пару +за цим шляхом. + +### Створення Гаманця + +Для взаємодії з мережею Solana за допомогою Solana CLI вам потрібен гаманець +Solana, поповнений SOL. + +Щоб створити ключову пару за замовчуванням у Keypair Path, виконайте наступну +команду: + +```shell +solana-keygen new +``` + +Ви повинні побачити результат, схожий на наступний: + +``` +Generating a new keypair + +For added security, enter a BIP39 passphrase + +NOTE! This passphrase improves security of the recovery seed phrase NOT the +keypair file itself, which is stored as insecure plain text + +BIP39 Passphrase (empty for none): + +Wrote new keypair to /Users/test/.config/solana/id.json +=========================================================================== +pubkey: 8dBTPrjnkXyuQK3KDt9wrZBfizEZijmmUQXVHpFbVwGT +=========================================================================== +Save this seed phrase and your BIP39 passphrase to recover your new keypair: +cream bleak tortoise ocean nasty game gift forget fancy salon mimic amazing +=========================================================================== +``` + + + +Якщо у вас вже є гаманець у файловій системі, збережений у місці за +замовчуванням, ця команда **НЕ** перезапише його, якщо ви явно не використаєте +прапорець `--force`. + + + +Після створення ключової пари ви можете отримати адресу (публічний ключ) цієї +пари за допомогою наступної команди: + +```shell +solana address +``` + +### Airdrop SOL + +Після налаштування локального гаманця запросіть airdrop SOL для поповнення +вашого гаманця. SOL потрібні для оплати комісій за транзакції та розгортання +програм. + +Встановіть ваш кластер на devnet: + +```shell +solana config set -ud +``` + +Далі запросіть airdrop SOL у devnet: + +```shell +solana airdrop 2 +``` + +Щоб перевірити баланс SOL вашого гаманця, виконайте наступну команду: + +```shell +solana balance +``` + + + +Команда `solana airdrop` наразі обмежена 5 SOL за запит у devnet. Помилки можуть +виникати через обмеження частоти запитів. + +Як альтернативу, ви можете отримати SOL у devnet за допомогою +[Solana Web Faucet](https://faucet.solana.com). + + + +### Запуск Локального Валідатора + +Solana CLI постачається з вбудованим +[тестовим валідатором](https://docs.anza.xyz/cli/examples/test-validator). +Запуск локального валідатора дозволить вам розгортати та тестувати програми +локально. + +У окремому терміналі виконайте наступну команду, щоб запустити локальний +валідатор: + +```shell +solana-test-validator +``` + + + +У WSL вам може знадобитися спочатку перейти до папки, де у вас є права запису за +замовчуванням: + +```shell +cd ~ +mkdir validator +cd validator +solana-test-validator +``` + + + +Переконайтеся, що оновили конфігурацію Solana CLI до `localhost` перед +виконанням команд: + +```shell +solana config set -ul +``` + + diff --git a/docs/locales/uk/intro/quick-start/cross-program-invocation.md b/docs/locales/uk/intro/quick-start/cross-program-invocation.md new file mode 100644 index 000000000..efc88ee2b --- /dev/null +++ b/docs/locales/uk/intro/quick-start/cross-program-invocation.md @@ -0,0 +1,607 @@ +--- +sidebarLabel: Крос-програмні виклики +title: Крос-програмні виклики +sidebarSortOrder: 5 +description: + Дізнайтеся, як реалізувати крос-програмні виклики (CPIs) у програмах Solana за + допомогою фреймворку Anchor. У цьому підручнику демонструється, як здійснювати + переказ SOL між акаунтами, взаємодіяти з Системною програмою та працювати з + адресами, отриманими від програми (PDAs), у CPIs. Ідеально підходить для + розробників, які хочуть створювати інтегровані програми Solana. +--- + +У цьому розділі ми оновимо програму CRUD з попереднього розділу про PDA, щоб +додати крос-програмні виклики (CPIs). Ми модифікуємо програму, щоб забезпечити +переказ SOL між акаунтами в інструкціях `update` та `delete`, демонструючи, як +взаємодіяти з іншими програмами (у цьому випадку з Системною програмою) +зсередини нашої програми. + +Метою цього розділу є покрокове пояснення процесу реалізації CPIs у програмі +Solana за допомогою фреймворку Anchor, спираючись на концепції PDA, які ми +розглядали в попередньому розділі. Для отримання додаткової інформації перейдіть +на сторінку [Крос-програмні виклики](/docs/uk/core/cpi). + + + +### Модифікація інструкції Update + +Спочатку ми реалізуємо простий механізм "оплати за оновлення" шляхом модифікації +структури `Update` та функції `update`. + +Розпочнемо з оновлення файлу `lib.rs`, щоб включити до області видимості +елементи з модуля `system_program`. + +```rs filename="lib.rs" +use anchor_lang::system_program::{transfer, Transfer}; +``` + + + + +```diff + use anchor_lang::prelude::*; ++ use anchor_lang::system_program::{transfer, Transfer}; +``` + + + + +Далі оновіть структуру Update, щоб включити додатковий акаунт під назвою +`vault_account`. Цей акаунт, який контролюється нашою програмою, отримуватиме +SOL від користувача, коли той оновлює свій акаунт повідомлень. + +```rs filename="lib.rs" +#[account( + mut, + seeds = [b"vault", user.key().as_ref()], + bump, +)] +pub vault_account: SystemAccount<'info>, +``` + + + + +```diff +#[derive(Accounts)] +#[instruction(message: String)] +pub struct Update<'info> { + #[account(mut)] + pub user: Signer<'info>, + ++ #[account( ++ mut, ++ seeds = [b"vault", user.key().as_ref()], ++ bump, ++ )] ++ pub vault_account: SystemAccount<'info>, + #[account( + mut, + seeds = [b"message", user.key().as_ref()], + bump = message_account.bump, + realloc = 8 + 32 + 4 + message.len() + 1, + realloc::payer = user, + realloc::zero = true, + )] + pub message_account: Account<'info, MessageAccount>, + pub system_program: Program<'info, System>, +} +``` + + + +Ми додаємо новий акаунт під назвою `vault_account` до нашої структури `Update`. Цей акаунт служить програмно-контрольованим "сейфом", який буде отримувати SOL від користувачів, коли вони оновлюють свої повідомлення. + +Використовуючи PDA (Program Derived Address) для сейфа, ми створюємо +програмно-контрольований акаунт, унікальний для кожного користувача, що дозволяє +нам управляти коштами користувачів у межах логіки нашої програми. + +--- + +Основні аспекти `vault_account`: + +- **Адреса акаунта**: + Адреса акаунта є PDA, що отримується за допомогою сідів: + `[b"vault", user.key().as_ref()]` +- **Відсутність приватного ключа**: + Оскільки це PDA, він не має приватного ключа, тому лише наша програма може + "підписуватися" за цю адресу під час виконання CPIs. +- **Тип акаунта**: + Це акаунт типу `SystemAccount`, який належить до Системної програми, як і + звичайні гаманці. + +--- + +Ця структура дозволяє нашій програмі: + +- Генерувати унікальні, детерміновані адреси для кожного "сейфа" користувача. +- Контролювати кошти без необхідності використання приватного ключа для + підписання транзакцій. + +--- + +У інструкції `delete` ми покажемо, як наша програма може "підписуватися" за цей +PDA під час CPI. + +--- + +Далі: реалізуйте логіку CPI в інструкції `update` + +Реалізуйте логіку CPI для переказу **0.001 SOL** з акаунта користувача на акаунт +сейфа. + +```rs filename="lib.rs" +let transfer_accounts = Transfer { + from: ctx.accounts.user.to_account_info(), + to: ctx.accounts.vault_account.to_account_info(), +}; +let cpi_context = CpiContext::new( + ctx.accounts.system_program.to_account_info(), + transfer_accounts, +); +transfer(cpi_context, 1_000_000)?; +``` + + + + +```diff + pub fn update(ctx: Context, message: String) -> Result<()> { + msg!("Update Message: {}", message); + let account_data = &mut ctx.accounts.message_account; + account_data.message = message; + ++ let transfer_accounts = Transfer { ++ from: ctx.accounts.user.to_account_info(), ++ to: ctx.accounts.vault_account.to_account_info(), ++ }; ++ let cpi_context = CpiContext::new( ++ ctx.accounts.system_program.to_account_info(), ++ transfer_accounts, ++ ); ++ transfer(cpi_context, 1_000_000)?; + Ok(()) + } +``` + + + + +В інструкції `update` ми реалізуємо виклик між програмами (CPI), щоб викликати +інструкцію `transfer` Системної програми. Це демонструє, як виконати CPI у межах +нашої програми, забезпечуючи композиційність програм у Solana. + +Структура `Transfer` визначає необхідні акаунти для інструкції `transfer` +Системної програми: + +- `from` - Акаунт користувача (джерело коштів) +- `to` - Акаунт сейфа (ціль для переказу коштів) + + ```rs filename="lib.rs" + let transfer_accounts = Transfer { + from: ctx.accounts.user.to_account_info(), + to: ctx.accounts.vault_account.to_account_info(), + }; + ``` + + `CpiContext` визначає: + +- Програму, яку потрібно викликати (Системна програма) +- Акаунти, необхідні для CPI (визначені у структурі `Transfer`) + + ```rs filename="lib.rs" + let cpi_context = CpiContext::new( + ctx.accounts.system_program.to_account_info(), + transfer_accounts, + ); + ``` + +Функція `transfer` викликає інструкцію переказу у Системній програмі, передаючи: + +- `cpi_context` (програму та акаунти) +- Суму для переказу (1,000,000 лампортів, що еквівалентно 0.001 SOL) + + ```rs filename="lib.rs" + transfer(cpi_context, 1_000_000)?; + ``` + +--- + +Налаштування для CPI відповідає тому, як створюються інструкції на стороні +клієнта, де ми вказуємо програму, акаунти та дані інструкції для виклику +конкретної інструкції. Коли викликається інструкція `update` нашої програми, +вона внутрішньо викликає інструкцію переказу Системної програми. + + + + +Перекомпілюйте програму. + +```shell filename="Terminal" +build +``` + +### Змініть Інструкцію Delete + +Ми реалізуємо механізм "повернення коштів при видаленні", змінивши структуру +`Delete` та функцію `delete`. + +Спершу оновіть структуру `Delete`, додавши до неї `vault_account`. Це дозволить +нам переказати всі SOL із сейфа назад користувачеві, коли він закриває свій +акаунт повідомлення. + +```rs filename="lib.rs" +#[account( + mut, + seeds = [b"vault", user.key().as_ref()], + bump, +)] +pub vault_account: SystemAccount<'info>, +``` + +Також додайте `system_program`, оскільки CPI для переказу вимагає виклику +Системної програми. + +```rs filename="lib.rs" +pub system_program: Program<'info, System>, +``` + + + + +```diff +#[derive(Accounts)] +pub struct Delete<'info> { + #[account(mut)] + pub user: Signer<'info>, + ++ #[account( ++ mut, ++ seeds = [b"vault", user.key().as_ref()], ++ bump, ++ )] ++ pub vault_account: SystemAccount<'info>, + #[account( + mut, + seeds = [b"message", user.key().as_ref()], + bump = message_account.bump, + close= user, + )] + pub message_account: Account<'info, MessageAccount>, ++ pub system_program: Program<'info, System>, +} +``` + + + + +Акаунт `vault_account` використовує той самий PDA, що і в структурі `Update`. + +Додавання `vault_account` до структури `Delete` дозволяє нашій програмі отримати +доступ до сейфа користувача під час виконання інструкції видалення, щоб +переказати накопичені SOL назад користувачеві. + + + + +Далі реалізуйте логіку CPI в інструкції `delete`, щоб переказати SOL із сейфа +назад на акаунт користувача. + +```rs filename="lib.rs" +let user_key = ctx.accounts.user.key(); +let signer_seeds: &[&[&[u8]]] = + &[&[b"vault", user_key.as_ref(), &[ctx.bumps.vault_account]]]; + +let transfer_accounts = Transfer { + from: ctx.accounts.vault_account.to_account_info(), + to: ctx.accounts.user.to_account_info(), +}; +let cpi_context = CpiContext::new( + ctx.accounts.system_program.to_account_info(), + transfer_accounts, +).with_signer(signer_seeds); +transfer(cpi_context, ctx.accounts.vault_account.lamports())?; +``` + +Зверніть увагу, що ми оновили `_ctx: Context` до `ctx: Context`, +оскільки будемо використовувати контекст у тілі функції. + + + + +```diff +- pub fn delete(_ctx: Context) -> Result<()> { ++ pub fn delete(ctx: Context) -> Result<()> { + msg!("Delete Message"); + ++ let user_key = ctx.accounts.user.key(); ++ let signer_seeds: &[&[&[u8]]] = ++ &[&[b"vault", user_key.as_ref(), &[ctx.bumps.vault_account]]]; ++ ++ let transfer_accounts = Transfer { ++ from: ctx.accounts.vault_account.to_account_info(), ++ to: ctx.accounts.user.to_account_info(), ++ }; ++ let cpi_context = CpiContext::new( ++ ctx.accounts.system_program.to_account_info(), ++ transfer_accounts, ++ ).with_signer(signer_seeds); ++ transfer(cpi_context, ctx.accounts.vault_account.lamports())?; + Ok(()) + } + +``` + + + +В інструкції `delete` ми реалізуємо ще один виклик між програмами (CPI), щоб викликати інструкцію переказу Системної програми. Цей CPI демонструє, як здійснити переказ, який потребує підписувача на основі Program Derived Address (PDA). + +Спершу ми визначаємо сіди для підпису PDA сейфа: + +```rs filename="lib.rs" +let user_key = ctx.accounts.user.key(); +let signer_seeds: &[&[&[u8]]] = + &[&[b"vault", user_key.as_ref(), &[ctx.bumps.vault_account]]]; +``` + +Структура `Transfer` визначає необхідні акаунти для інструкції переказу +Системної програми: + +- `from`: Акаунт сейфа (джерело коштів) +- `to`: Акаунт користувача (ціль для переказу коштів) + + ```rs filename="lib.rs" + let transfer_accounts = Transfer { + from: ctx.accounts.vault_account.to_account_info(), + to: ctx.accounts.user.to_account_info(), + }; + ``` + + `CpiContext` визначає: + +- Програму, яку потрібно викликати (Системна програма) +- Акаунти, задіяні у переказі (визначені у структурі `Transfer`) +- Сіди для підпису PDA + + ```rs filename="lib.rs" + let cpi_context = CpiContext::new( + ctx.accounts.system_program.to_account_info(), + transfer_accounts, + ).with_signer(signer_seeds); + ``` + + Функція `transfer` викликає інструкцію переказу в Системній програмі, + передаючи: + +- `cpi_context` (програму, акаунти та підписувач на основі PDA) +- Суму для переказу (весь баланс акаунта сейфа) + + ```rs filename="lib.rs" + transfer(cpi_context, ctx.accounts.vault_account.lamports())?; + ``` + + Ця реалізація CPI демонструє, як програми можуть використовувати PDA для + управління коштами. Коли викликається інструкція `delete` нашої програми, вона + внутрішньо викликає інструкцію переказу Системної програми, підписуючи за PDA, + щоб авторизувати переказ усіх коштів із сейфа назад користувачеві. + + + + +Перекомпілюйте програму. + +```shell filename="Terminal" +build +``` + +### Розгортання Програми + +Після внесення цих змін нам потрібно повторно розгорнути оновлену програму. Це +забезпечує доступність модифікованої програми для тестування. У Solana оновлення +програми вимагає лише розгортання скомпільованої програми за тим самим +ідентифікатором програми (program ID). + +```shell filename="Terminal" +deploy +``` + + + + +```bash +$ deploy +Deploying... This could take a while depending on the program size and network conditions. +Deployment successful. Completed in 17s. +``` + + + + +Лише орган влади оновлення (upgrade authority) програми може її оновити. Орган +влади оновлення встановлюється під час розгортання програми, і це єдиний акаунт, +який має дозвіл модифікувати або закривати програму. Якщо орган влади оновлення +відкликається, програма стає незмінною і її ніколи не можна буде закрити або +оновити. + +Під час розгортання програм у Solana Playground гаманцем Playground є орган +влади оновлення для всіх ваших програм. + + + + +### Оновлення Файлу Тестів + +Далі ми оновимо наш файл `anchor.test.ts`, щоб включити новий акаунт сейфа у +наші інструкції. Це вимагає отримання PDA сейфа та його включення до викликів +інструкцій `update` і `delete`. + +#### Отримання PDA Сейфа + +Спершу додайте код для отримання PDA сейфа: + +```ts filename="anchor.test.ts" +const [vaultPda, vaultBump] = PublicKey.findProgramAddressSync( + [Buffer.from("vault"), wallet.publicKey.toBuffer()], + program.programId, +); +``` + + + + +```diff +describe("pda", () => { + const program = pg.program; + const wallet = pg.wallet; + + const [messagePda, messageBump] = PublicKey.findProgramAddressSync( + [Buffer.from("message"), wallet.publicKey.toBuffer()], + program.programId + ); + ++ const [vaultPda, vaultBump] = PublicKey.findProgramAddressSync( ++ [Buffer.from("vault"), wallet.publicKey.toBuffer()], ++ program.programId ++ ); + + // ...tests + }); +``` + + + +#### Зміна Тесту Update + +Далі оновіть інструкцію `update`, щоб включити `vaultAccount`. + +```ts filename="anchor.test.ts" {5} +const transactionSignature = await program.methods + .update(message) + .accounts({ + messageAccount: messagePda, + vaultAccount: vaultPda, + }) + .rpc({ commitment: "confirmed" }); +``` + + + + +```diff + const transactionSignature = await program.methods + .update(message) + .accounts({ + messageAccount: messagePda, ++ vaultAccount: vaultPda, + }) + .rpc({ commitment: "confirmed" }); +``` + + + + +#### Зміна Тесту Delete + +Далі оновіть інструкцію `delete`, щоб включити `vaultAccount`. + +```ts filename="anchor.test.ts" {5} +const transactionSignature = await program.methods + .delete() + .accounts({ + messageAccount: messagePda, + vaultAccount: vaultPda, + }) + .rpc({ commitment: "confirmed" }); +``` + + + + +```diff + const transactionSignature = await program.methods + .delete() + .accounts({ + messageAccount: messagePda, ++ vaultAccount: vaultPda, + }) + .rpc({ commitment: "confirmed" }); +``` + + + +### Перезапуск Тестів + +Після внесення цих змін запустіть тести, щоб переконатися, що все працює, як +очікувалося: + +```shell filename="Terminal" +test +``` + + + + +```bash +$ test +Running tests... + anchor.test.ts: + pda + { + "user": "3z9vL1zjN6qyAFHhHQdWYRTFAcy69pJydkZmSFBKHg1R", + "message": "Hello, World!", + "bump": 254 +} + Transaction Signature: https://solana.fm/tx/qGsYb87mUUjeyh7Ha7r9VXkACw32HxVBujo2NUxqHiUc8qxRMFB7kdH2D4JyYtPBx171ddS91VyVrFXypgYaKUr?cluster=devnet-solana + ✔ Create Message Account (842ms) + { + "user": "3z9vL1zjN6qyAFHhHQdWYRTFAcy69pJydkZmSFBKHg1R", + "message": "Hello, Solana!", + "bump": 254 +} + Transaction Signature: https://solana.fm/tx/3KCDnNSfDDfmSy8kpiSrJsGGkzgxx2mt18KejuV2vmJjeyenkSoEfs2ghUQ6cMoYYgd9Qax9CbnYRcvF2zzumNt8?cluster=devnet-solana + ✔ Update Message Account (946ms) + Expect Null: null + Transaction Signature: https://solana.fm/tx/3M7Z7Mea3TtQc6m9z386B9QuEgvLKxD999mt2RyVtJ26FgaAzV1QA5mxox3eXie3bpBkNpDQ4mEANr3trVHCWMC2?cluster=devnet-solana + ✔ Delete Message Account (859ms) + 3 passing (3s) +``` + + + +Після цього ви можете переглянути посилання SolanFM, щоб побачити деталі транзакції, де ви знайдете CPI для інструкцій переказу в межах інструкцій `update` і `delete`. + +![Update CPI](/assets/docs/intro/quickstart/cpi-update.png) + +![Delete CPI](/assets/docs/intro/quickstart/cpi-delete.png) + +Якщо ви зіткнулися з помилками, ви можете переглянути +[фінальний код](https://beta.solpg.io/668304cfcffcf4b13384d20a). + + + +## Наступні Кроки + +Ви завершили посібник з швидкого старту Solana! Ви дізналися про акаунти, +транзакції, PDA, CPI та розгорнули власні програми. + +Відвідайте сторінки [Основні Концепції](/docs/uk/core/accounts) для більш +детального пояснення тем, розглянутих у цьому посібнику. + +Додаткові навчальні матеріали доступні на сторінці +[Ресурси для Розробників](/developers). + +### Досліджуйте Більше Прикладів + +Якщо ви віддаєте перевагу навчанню через приклади, перегляньте +[Репозиторій з Прикладами Програм](https://github.com/solana-developers/program-examples) +для різноманітних прикладів програм. + +Solana Playground пропонує зручну функцію, яка дозволяє імпортувати або +переглядати проєкти за їх посиланнями на GitHub. Наприклад, відкрийте це +[посилання Solana Playground](https://beta.solpg.io/https://github.com/solana-developers/program-examples/tree/main/basics/hello-solana/anchor), +щоб переглянути Anchor-проєкт із цього +[репозиторію GitHub](https://github.com/solana-developers/program-examples/tree/main/basics/hello-solana/anchor). + +Натисніть кнопку `Import` і введіть ім'я проєкту, щоб додати його до свого +списку проєктів у Solana Playground. Після імпорту проєкту всі зміни автоматично +зберігаються та залишаються у середовищі Playground. diff --git a/docs/locales/uk/intro/quick-start/deploying-programs.md b/docs/locales/uk/intro/quick-start/deploying-programs.md new file mode 100644 index 000000000..f81745580 --- /dev/null +++ b/docs/locales/uk/intro/quick-start/deploying-programs.md @@ -0,0 +1,374 @@ +--- +sidebarLabel: Розгортання Програм +title: Розгортання Вашої Першої Програми Solana +sidebarSortOrder: 3 +description: + Дізнайтеся, як створити, розгорнути та протестувати вашу першу програму Solana + за допомогою фреймворку Anchor та Solana Playground. Цей посібник для + початківців демонструє, як створити просту програму, розгорнути її на devnet, + виконати тести та закрити програму. +--- + +У цьому розділі ми створимо, розгорнемо та протестуємо просту програму Solana за +допомогою фреймворку Anchor. Наприкінці ви розгорнете свою першу програму у +блокчейні Solana! + +Мета цього розділу — ознайомити вас із Solana Playground. Ми розглянемо більш +детальний приклад у розділах про PDA та CPI. Для отримання додаткової інформації +відвідайте сторінку [Програми на Solana](/docs/core/programs). + + + +### Створення Проєкту Anchor + +Спочатку відкрийте https://beta.solpg.io у новій вкладці браузера. + +- Натисніть кнопку "Create a new project" у лівій панелі. + +- Введіть назву проєкту, виберіть Anchor як фреймворк, потім натисніть кнопку + "Create". + +![Новий Проєкт](/assets/docs/intro/quickstart/pg-new-project.gif) + +Ви побачите створений проєкт із кодом програми у файлі `src/lib.rs`. + +```rust filename="lib.rs" +use anchor_lang::prelude::*; + +// This is your program's public key and it will update +// automatically when you build the project. +declare_id!("11111111111111111111111111111111"); + +#[program] +mod hello_anchor { + use super::*; + pub fn initialize(ctx: Context, data: u64) -> Result<()> { + ctx.accounts.new_account.data = data; + msg!("Changed data to: {}!", data); // Message will show up in the tx logs + Ok(()) + } +} + +#[derive(Accounts)] +pub struct Initialize<'info> { + // We must specify the space in order to initialize an account. + // First 8 bytes are default account discriminator, + // next 8 bytes come from NewAccount.data being type u64. + // (u64 = 64 bits unsigned integer = 8 bytes) + #[account(init, payer = signer, space = 8 + 8)] + pub new_account: Account<'info, NewAccount>, + #[account(mut)] + pub signer: Signer<'info>, + pub system_program: Program<'info, System>, +} + +#[account] +pub struct NewAccount { + data: u64 +} +``` + + + +На даний момент ми розглянемо лише загальний огляд коду програми: + +- Макрос `declare_id!` визначає адресy вашої програми у блокчейні. Ця адреса + буде автоматично оновлена, коли ми скомпілюємо програму на наступному етапі. + + ```rs + declare_id!("11111111111111111111111111111111"); + ``` + +- Макрос `#[program]` позначає модуль, який містить функції, що представляють + інструкції програми. + + ```rs + #[program] + mod hello_anchor { + use super::*; + pub fn initialize(ctx: Context, data: u64) -> Result<()> { + ctx.accounts.new_account.data = data; + msg!("Changed data to: {}!", data); // Message will show up in the tx logs + Ok(()) + } + } + ``` + + У цьому прикладі інструкція `initialize` приймає два параметри: + +1. `ctx: Context` — надає доступ до акаунтів, необхідних для цієї + інструкції, як це зазначено у структурі `Initialize`. +2. `data: u64` — параметр інструкції, який передається під час виклику + інструкції. + +Тіло функції встановлює значення поля `data` для `new_account` відповідно до +переданого аргументу `data`, а потім виводить повідомлення до журналу програми. + +- Макрос `#[derive(Accounts)]` використовується для визначення структури, яка + задає акаунти, необхідні для певної інструкції, де кожне поле представляє + окремий акаунт. + +Типи полів (наприклад, `Signer<'info>`) і обмеження (наприклад, +`#[account(mut)]`) використовуються Anchor для автоматичного виконання +стандартних перевірок безпеки, пов'язаних із валідацією акаунтів. + +```rs +#[derive(Accounts)] +pub struct Initialize<'info> { + #[account(init, payer = signer, space = 8 + 8)] + pub new_account: Account<'info, NewAccount>, + #[account(mut)] + pub signer: Signer<'info>, + pub system_program: Program<'info, System>, +} +``` + +- Макрос `#[account]` використовується для визначення структури, яка представляє + структуру даних акаунта, створеного та керованого програмою. + + ```rs + #[account] + pub struct NewAccount { + data: u64 + } + ``` + + + + +### Скомпілюйте та Розгорніть Програму + +Щоб скомпілювати програму, просто виконайте команду `build` у терміналі. + +```shell filename="Terminal" +build +``` + +Зверніть увагу, що адреса у `declare_id!()` була оновлена. Це адреса вашої +програми у блокчейні. + + + + +```shell filename="Terminal" +$ build +Building... +Build successful. Completed in 1.46s. +``` + + + +Після компіляції програми виконайте команду `deploy` у терміналі, щоб розгорнути програму в мережі (за замовчуванням devnet). Для розгортання програми необхідно виділити SOL для акаунта у блокчейні, який зберігатиме програму. + +Перед розгортанням переконайтеся, що у вас достатньо SOL. Ви можете отримати +devnet SOL, виконавши команду `solana airdrop 5` у терміналі Playground або +скориставшись [веб-фонтаном](https://faucet.solana.com/). + +```shell filename="Terminal" +deploy +``` + + + + +```shell filename="Terminal" +$ deploy +Deploying... This could take a while depending on the program size and network conditions. +Warning: 1 transaction not confirmed, retrying... +Deployment successful. Completed in 19s. +``` + + + + +Альтернативно, ви також можете скористатися кнопками `Build` і `Deploy` на лівій +панелі. + +![Build and Deploy](/assets/docs/intro/quickstart/pg-build-deploy.png) + +Після розгортання програми ви можете викликати її інструкції. + +### Тестування Програми + +Разом із стартовим кодом включений тестовий файл, який знаходиться у +`tests/anchor.test.ts`. У цьому файлі показано, як викликати інструкцію +`initialize` у стартовій програмі з клієнта. + +```ts filename="anchor.test.ts" +// No imports needed: web3, anchor, pg and more are globally available + +describe("Test", () => { + it("initialize", async () => { + // Generate keypair for the new account + const newAccountKp = new web3.Keypair(); + + // Send transaction + const data = new BN(42); + const txHash = await pg.program.methods + .initialize(data) + .accounts({ + newAccount: newAccountKp.publicKey, + signer: pg.wallet.publicKey, + systemProgram: web3.SystemProgram.programId, + }) + .signers([newAccountKp]) + .rpc(); + console.log(`Use 'solana confirm -v ${txHash}' to see the logs`); + + // Confirm transaction + await pg.connection.confirmTransaction(txHash); + + // Fetch the created account + const newAccount = await pg.program.account.newAccount.fetch( + newAccountKp.publicKey, + ); + + console.log("On-chain data is:", newAccount.data.toString()); + + // Check whether the data on-chain is equal to local 'data' + assert(data.eq(newAccount.data)); + }); +}); +``` + +Щоб запустити тестовий файл після розгортання програми, виконайте команду `test` +у терміналі. + +```shell filename="Terminal" +test +``` + +Ви повинні побачити результат, який вказує, що тест пройшов успішно. + + + + +```shell filename="Terminal" +$ test +Running tests... + hello_anchor.test.ts: + hello_anchor + Use 'solana confirm -v 3TewJtiUz1EgtT88pLJHvKFzqrzDNuHVi8CfD2mWmHEBAaMfC5NAaHdmr19qQYfTiBace6XUmADvR4Qrhe8gH5uc' to see the logs + On-chain data is: 42 + ✔ initialize (961ms) + 1 passing (963ms) +``` + + + +Ви також можете скористатися кнопкою `Test` на лівій панелі. + +![Run Test](/assets/docs/intro/quickstart/pg-test.png) + +Потім ви можете переглянути журнали транзакцій, виконавши команду +`solana confirm -v` та вказавши хеш транзакції (підпис) із результатів тесту: + +```shell filename="Terminal" +solana confirm -v [TxHash] +``` + +Наприклад: + +```shell filename="Terminal" +solana confirm -v 3TewJtiUz1EgtT88pLJHvKFzqrzDNuHVi8CfD2mWmHEBAaMfC5NAaHdmr19qQYfTiBace6XUmADvR4Qrhe8gH5uc +``` + + + + +```shell filename="Terminal" {29-35} +$ solana confirm -v 3TewJtiUz1EgtT88pLJHvKFzqrzDNuHVi8CfD2mWmHEBAaMfC5NAaHdmr19qQYfTiBace6XUmADvR4Qrhe8gH5uc +RPC URL: https://api.devnet.solana.com +Default Signer: Playground Wallet +Commitment: confirmed + +Transaction executed in slot 308150984: + Block Time: 2024-06-25T12:52:05-05:00 + Version: legacy + Recent Blockhash: 7AnZvY37nMhCybTyVXJ1umcfHSZGbngnm4GZx6jNRTNH + Signature 0: 3TewJtiUz1EgtT88pLJHvKFzqrzDNuHVi8CfD2mWmHEBAaMfC5NAaHdmr19qQYfTiBace6XUmADvR4Qrhe8gH5uc + Signature 1: 3TrRbqeMYFCkjsxdPExxBkLAi9SB2pNUyg87ryBaTHzzYtGjbsAz9udfT9AkrjSo1ZjByJgJHBAdRVVTZv6B87PQ + Account 0: srw- 3z9vL1zjN6qyAFHhHQdWYRTFAcy69pJydkZmSFBKHg1R (fee payer) + Account 1: srw- c7yy8zdP8oeZ2ewbSb8WWY2yWjDpg3B43jk3478Nv7J + Account 2: -r-- 11111111111111111111111111111111 + Account 3: -r-x 2VvQ11q8xrn5tkPNyeraRsPaATdiPx8weLAD8aD4dn2r + Instruction 0 + Program: 2VvQ11q8xrn5tkPNyeraRsPaATdiPx8weLAD8aD4dn2r (3) + Account 0: c7yy8zdP8oeZ2ewbSb8WWY2yWjDpg3B43jk3478Nv7J (1) + Account 1: 3z9vL1zjN6qyAFHhHQdWYRTFAcy69pJydkZmSFBKHg1R (0) + Account 2: 11111111111111111111111111111111 (2) + Data: [175, 175, 109, 31, 13, 152, 155, 237, 42, 0, 0, 0, 0, 0, 0, 0] + Status: Ok + Fee: ◎0.00001 + Account 0 balance: ◎5.47001376 -> ◎5.46900152 + Account 1 balance: ◎0 -> ◎0.00100224 + Account 2 balance: ◎0.000000001 + Account 3 balance: ◎0.00139896 + Log Messages: + Program 2VvQ11q8xrn5tkPNyeraRsPaATdiPx8weLAD8aD4dn2r invoke [1] + Program log: Instruction: Initialize + Program 11111111111111111111111111111111 invoke [2] + Program 11111111111111111111111111111111 success + Program log: Changed data to: 42! + Program 2VvQ11q8xrn5tkPNyeraRsPaATdiPx8weLAD8aD4dn2r consumed 5661 of 200000 compute units + Program 2VvQ11q8xrn5tkPNyeraRsPaATdiPx8weLAD8aD4dn2r success + +Confirmed +``` + + + + +Альтернативно, ви можете переглянути деталі транзакції на +[SolanaFM](https://solana.fm/) або +[Solana Explorer](https://explorer.solana.com/?cluster=devnet), здійснивши пошук +за підписом (хешем) транзакції. + + + Нагадуємо, що потрібно оновити підключення до кластеру (мережі) у вибраному Explorer, щоб воно відповідало кластеру Solana Playground. За замовчуванням у Solana Playground використовується кластер devnet. + + +### Закриття Програми + +Нарешті, SOL, виділений для програми у блокчейні, може бути повністю повернутий +шляхом закриття програми. + +Ви можете закрити програму, виконавши наступну команду та вказавши адресу +програми, яка знаходиться у `declare_id!()`: + +```shell filename="Terminal" +solana program close [ProgramID] +``` + +Наприклад: + +```shell filename="Terminal" +solana program close 2VvQ11q8xrn5tkPNyeraRsPaATdiPx8weLAD8aD4dn2r +``` + + + + +```shell filename="Terminal" +$ solana program close 2VvQ11q8xrn5tkPNyeraRsPaATdiPx8weLAD8aD4dn2r +Closed Program Id 2VvQ11q8xrn5tkPNyeraRsPaATdiPx8weLAD8aD4dn2r, 2.79511512 SOL reclaimed +``` + + + + +Тільки орган влади оновлення програми може її закрити. Орган влади оновлення +встановлюється під час розгортання програми, і це єдиний акаунт, який має дозвіл +модифікувати або закривати програму. Якщо орган влади оновлення відкликається, +програма стає незмінною і її ніколи не можна буде закрити або оновити. + +Під час розгортання програм у Solana Playground гаманцем Playground є орган +влади оновлення для всіх ваших програм. + + + + +Вітаємо! Ви щойно створили та розгорнули свою першу програму Solana за допомогою +фреймворку Anchor! + + diff --git a/docs/locales/uk/intro/quick-start/index.md b/docs/locales/uk/intro/quick-start/index.md new file mode 100644 index 000000000..3d22ddc46 --- /dev/null +++ b/docs/locales/uk/intro/quick-start/index.md @@ -0,0 +1,118 @@ +--- +sidebarLabel: Швидкий Старт +title: Посібник з Швидкого Старту Solana +sidebarSortOrder: 0 +description: + Вивчіть основи розробки на Solana. Створіть свою першу програму, дізнайтеся + про акаунти, надсилайте транзакції та досліджуйте PDA та CPI за допомогою + Solana Playground – без необхідності встановлення. +--- + +Ласкаво просимо до посібника з швидкого старту Solana! Цей практичний посібник +ознайомить вас із ключовими концепціями створення програм на Solana, незалежно +від вашого попереднього досвіду. Після завершення цього уроку у вас буде базове +розуміння розробки на Solana, і ви зможете досліджувати більш складні теми. + +## Чого Ви Навчитеся + +У цьому уроці ви дізнаєтеся про: + +- **Розуміння акаунтів**: Дослідження зберігання даних у мережі Solana. +- **Надсилання транзакцій**: Взаємодія з мережею Solana шляхом надсилання + транзакцій. +- **Створення та розгортання програм**: Створіть свою першу програму Solana та + розгорніть її в мережі. +- **Program Derived Addresses (PDA)**: Як використовувати PDA для створення + детермінованих адрес акаунтів. +- **Cross-Program Invocations (CPI)**: Як зробити так, щоб ваші програми + взаємодіяли з іншими програмами на Solana. + +Найкраще те, що вам нічого не потрібно встановлювати! Ми будемо використовувати +Solana Playground, браузерне середовище розробки, для всіх наших прикладів. Це +означає, що ви можете слідувати урокам, копіювати та вставляти код і одразу +бачити результати прямо у вашому браузері. Базові знання програмування бажані, +але не обов’язкові. + +Давайте почнемо будувати на Solana! + +## Solana Playground + +Solana Playground (Solpg) – це браузерне середовище розробки, яке дозволяє +швидко розробляти, розгортати та тестувати програми Solana! + +Відкрийте нову вкладку у своєму браузері та перейдіть на +[https://beta.solpg.io/](https://beta.solpg.io/). + + + +### Створення Гаманця Playground + +Якщо ви новачок у Solana Playground, першим кроком буде створення гаманця +Playground. Цей гаманець дозволить вам взаємодіяти з мережею Solana +безпосередньо з вашого браузера. + +#### Крок 1. Підключіться до Playground + +Натисніть кнопку "Not connected" у нижньому лівому куті екрана. + +![Not Connected](/assets/docs/intro/quickstart/pg-not-connected.png) + +#### Крок 2. Створіть Свій Гаманець + +Вам буде запропоновано зберегти ключову пару вашого гаманця. За бажанням +збережіть ключову пару для резервної копії, а потім натисніть "Continue". + +![Create Playground Wallet](/assets/docs/intro/quickstart/pg-create-wallet.png) + +Тепер ви повинні побачити адресу вашого гаманця, баланс SOL і підключений +кластер (за замовчуванням devnet) у нижній частині вікна. + +![Connected](/assets/docs/intro/quickstart/pg-connected.png) + + + Ваш гаманець Playground зберігається у локальному сховищі вашого браузера. Очистка кешу браузера видалить ваш збережений гаманець. + + +Декілька корисних визначень: + +- **_адреса гаманця_**: Унікальний ідентифікатор цифрового гаманця, який + використовується для надсилання або отримання криптоактивів у блокчейні. Це + схоже на електронну адресу чи номер банківського рахунку – щоб хтось надіслав + вам криптовалюту, йому потрібна ваша адреса гаманця. +- **_підключений кластер_**: Набір вузлів мережі, які працюють разом, щоб + підтримувати синхронізовану копію блокчейна. Кластери важливі для надання + децентралізованого розподіленого реєстру, перевірки транзакцій, забезпечення + безпеки ланцюга та виконання програм (смарт-контрактів). + +### Отримання Devnet SOL + +Перед тим як почати розробку, нам потрібен devnet SOL. + +З точки зору розробника, SOL потрібен для двох основних цілей: + +- Для створення акаунтів, де можна зберігати дані або розгортати програми +- Для сплати комісій за транзакції під час взаємодії з мережею + +Нижче наведено два способи поповнити ваш гаманець devnet SOL: + +#### Варіант 1: Використання Терміналу Playground + +Щоб поповнити ваш гаманець Playground devnet SOL, виконайте у терміналі +Playground команду: + +```shell filename="Terminal" +solana airdrop 5 +``` + +#### Варіант 2: Використання Devnet Faucet + +Якщо команда airdrop не працює (через обмеження або помилки), скористайтеся +[Web Faucet](https://faucet.solana.com/). + +- Введіть адресу свого гаманця (знаходиться в нижній частині екрана Playground) + і виберіть суму +- Натисніть "Confirm Airdrop", щоб отримати ваш devnet SOL + +![Faucet Airdrop](/assets/docs/intro/quickstart/faucet-airdrop.gif) + + diff --git a/docs/locales/uk/intro/quick-start/program-derived-address.md b/docs/locales/uk/intro/quick-start/program-derived-address.md new file mode 100644 index 000000000..e259518a8 --- /dev/null +++ b/docs/locales/uk/intro/quick-start/program-derived-address.md @@ -0,0 +1,1100 @@ +--- +sidebarLabel: Program Derived Address +title: Програма Derived Address +sidebarSortOrder: 4 +description: + Дізнайтеся, як створити CRUD (Create, Read, Update, Delete) програму Solana, + використовуючи Program Derived Addresses (PDAs) і фреймворк Anchor. Цей + покроковий посібник демонструє, як створювати, оновлювати та видаляти акаунти + повідомлень у блокчейні за допомогою PDAs, реалізувати валідацію акаунтів і + писати тести. Ідеально для розробників, які хочуть зрозуміти, як + використовувати PDAs у програмах Solana. +--- + +У цьому розділі ми розглянемо, як створити базову CRUD (Create, Read, Update, +Delete) програму. Програма зберігатиме повідомлення користувача, використовуючи +Program Derived Address (PDA) як адресу акаунта. + +Мета цього розділу – провести вас через етапи створення і тестування програми +Solana, використовуючи фреймворк Anchor, і показати, як використовувати PDA у +програмі. Для отримання додаткової інформації відвідайте сторінку +[Programs Derived Address](/docs/uk/core/pda). + +Для довідки ось [фінальний код](https://beta.solpg.io/668304cfcffcf4b13384d20a), +завершений після розгляду розділів PDA і CPI. + + + +### Стартовий Код + +Почніть, відкривши це +[посилання на Solana Playground](https://beta.solpg.io/66734b7bcffcf4b13384d1ad) +зі стартовим кодом. Потім натисніть кнопку "Import", щоб додати програму до +вашого списку проєктів у Solana Playground. + +![Import](/assets/docs/intro/quickstart/pg-import.png) + +У файлі `lib.rs` ви знайдете шаблон програми з інструкціями `create`, `update` і +`delete`, які ми реалізуємо на наступних етапах. + +```rs filename="lib.rs" +use anchor_lang::prelude::*; + +declare_id!("8KPzbM2Cwn4Yjak7QYAEH9wyoQh86NcBicaLuzPaejdw"); + +#[program] +pub mod pda { + use super::*; + + pub fn create(_ctx: Context) -> Result<()> { + Ok(()) + } + + pub fn update(_ctx: Context) -> Result<()> { + Ok(()) + } + + pub fn delete(_ctx: Context) -> Result<()> { + Ok(()) + } +} + +#[derive(Accounts)] +pub struct Create {} + +#[derive(Accounts)] +pub struct Update {} + +#[derive(Accounts)] +pub struct Delete {} + +#[account] +pub struct MessageAccount {} +``` + +Перед початком виконайте команду `build` у терміналі Playground, щоб +переконатися, що стартова програма успішно компілюється. + +```shell filename="Terminal" +build +``` + + + + +```shell filename="Terminal" +$ build +Building... +Build successful. Completed in 3.50s. +``` + + + + +### Визначення Типу Акаунта Повідомлення + +Спочатку визначимо структуру акаунта повідомлення, який створюватиме наша +програма. Це дані, які ми зберігатимемо в акаунті, створеному програмою. + +У файлі `lib.rs` оновіть структуру `MessageAccount` наступним кодом: + +```rs filename="lib.rs" +#[account] +pub struct MessageAccount { + pub user: Pubkey, + pub message: String, + pub bump: u8, +} +``` + + + + +```diff +- #[account] +- pub struct MessageAccount {} + ++ #[account] ++ pub struct MessageAccount { ++ pub user: Pubkey, ++ pub message: String, ++ pub bump: u8, ++ } +``` + + + + +Макрос `#[account]` у програмі Anchor використовується для позначення структур, +які представляють дані акаунта (тип даних, що зберігається у полі даних +`AccountInfo`). + +У цьому прикладі ми визначаємо структуру `MessageAccount` для зберігання +повідомлення, створеного користувачами, яка містить три поля: + +- `user` — `Pubkey`, який представляє користувача, що створив акаунт + повідомлення. +- `message` — `String`, який містить повідомлення користувача. +- `bump` — `u8`, що зберігає ["bump" seed](/docs/uk/core/pda#canonical-bump), + використаний для отримання адреси, створеної програмою (PDA). Зберігання цього + значення економить обчислювальні ресурси, оскільки усуває необхідність + повторного обчислення для кожного використання в наступних інструкціях. + +Коли акаунт створюється, дані `MessageAccount` будуть серіалізовані та збережені +у полі даних нового акаунта. + +Пізніше, під час читання з акаунта, ці дані можна буде десеріалізувати назад у +тип даних `MessageAccount`. Процес створення та читання даних акаунта буде +продемонстровано у розділі тестування. + + + + +Скомпілюйте програму знову, виконавши команду `build` у терміналі. + +```shell filename="Terminal" +build +``` + +Ми визначили, як виглядатиме наш акаунт повідомлення. Далі ми реалізуємо +інструкції програми. + +### Реалізація Інструкції Create + +Тепер реалізуємо інструкцію `create` для створення та ініціалізації +`MessageAccount`. + +Почніть із визначення акаунтів, необхідних для цієї інструкції, оновивши +структуру `Create` наступним кодом: + +```rs filename="lib.rs" +#[derive(Accounts)] +#[instruction(message: String)] +pub struct Create<'info> { + #[account(mut)] + pub user: Signer<'info>, + + #[account( + init, + seeds = [b"message", user.key().as_ref()], + bump, + payer = user, + space = 8 + 32 + 4 + message.len() + 1 + )] + pub message_account: Account<'info, MessageAccount>, + pub system_program: Program<'info, System>, +} +``` + + + + +```diff +- #[derive(Accounts)] +- pub struct Create {} + ++ #[derive(Accounts)] ++ #[instruction(message: String)] ++ pub struct Create<'info> { ++ #[account(mut)] ++ pub user: Signer<'info>, ++ ++ #[account( ++ init, ++ seeds = [b"message", user.key().as_ref()], ++ bump, ++ payer = user, ++ space = 8 + 32 + 4 + message.len() + 1 ++ )] ++ pub message_account: Account<'info, MessageAccount>, ++ pub system_program: Program<'info, System>, ++ } +``` + + + +Макрос `#[derive(Accounts)]` у програмі Anchor використовується для позначення структур, які представляють список акаунтів, необхідних для інструкції, де кожне поле в структурі є акаунтом. + +Кожен акаунт (поле) у структурі позначається типом акаунта (наприклад, +`Signer<'info>`) і може бути додатково позначений обмеженнями (наприклад, +`#[account(mut)]`). Тип акаунта разом із обмеженнями акаунта використовуються +для виконання перевірок безпеки акаунтів, переданих до інструкції. + +Назви кожного поля використовуються лише для нашого розуміння і не впливають на +валідацію акаунтів, однак рекомендується використовувати описові імена акаунтів. + +--- + +Структура `Create` визначає акаунти, необхідні для інструкції `create`. + +1. `user: Signer<'info>` + + - Представляє користувача, який створює акаунт повідомлення. + - Позначений як змінний (`#[account(mut)]`), оскільки оплачує створення + нового акаунта. + - Повинен бути підписувачем, щоб підтвердити транзакцію, оскільки лампорти + будуть списані з акаунта. + +2. `message_account: Account<'info, MessageAccount>` + + - Новий акаунт, створений для зберігання повідомлення користувача. + - Обмеження `init` вказує, що акаунт буде створено в інструкції. + - Обмеження `seeds` і `bump` вказують, що адреса акаунта є Program Derived + Address (PDA). + - `payer = user` вказує акаунт, який оплачує створення нового акаунта. + - `space` вказує кількість байтів, виділених для поля даних нового акаунта. + +3. `system_program: Program<'info, System>` + + - Необхідна для створення нових акаунтів. + - На рівні механіки обмеження `init` викликає Системну програму для створення + нового акаунта з виділенням вказаного `space` та переназначає власника + програми на поточну програму. + +--- + +Анотація `#[instruction(message: String)]` дозволяє структурі `Create` +отримувати доступ до параметра `message` з інструкції `create`. + +--- + +Обмеження `seeds` і `bump` використовуються разом для вказівки, що адреса +акаунта є Program Derived Address (PDA). + +```rs filename="lib.rs" +seeds = [b"message", user.key().as_ref()], +bump, +``` + +Обмеження `seeds` визначає необов’язкові вхідні значення, які використовуються +для отримання PDA: + +- `b"message"` — Жорстко закодований рядок як перше значення seed. +- `user.key().as_ref()` — Публічний ключ акаунта `user` як друге значення seed. + +Обмеження `bump` вказує Anchor автоматично знайти та використовувати правильний +bump seed. Anchor використовує `seeds` і `bump` для отримання PDA. + +--- + +Розрахунок `space` (8 + 32 + 4 + message.len() + 1) виділяє простір для даних +типу `MessageAccount`: + +- Дискримінатор акаунта Anchor (ідентифікатор): 8 байтів +- Адреса користувача (Pubkey): 32 байти +- Повідомлення користувача (String): 4 байти для довжини + змінна довжина + повідомлення +- Bump seed для PDA (u8): 1 байт + +```rs filename="lib.rs" +#[account] +pub struct MessageAccount { + pub user: Pubkey, + pub message: String, + pub bump: u8, +} +``` + +Усі акаунти, створені за допомогою програми Anchor, вимагають 8 байтів для +дискримінатора акаунта, який є ідентифікатором типу акаунта і генерується +автоматично під час створення акаунта. + +Тип `String` вимагає 4 байти для зберігання довжини рядка, а решта — це фактичні +дані. + + + + +Далі реалізуйте бізнес-логіку для інструкції `create`, оновивши функцію `create` +наступним кодом: + +```rs filename="lib.rs" +pub fn create(ctx: Context, message: String) -> Result<()> { + msg!("Create Message: {}", message); + let account_data = &mut ctx.accounts.message_account; + account_data.user = ctx.accounts.user.key(); + account_data.message = message; + account_data.bump = ctx.bumps.message_account; + Ok(()) +} +``` + + + + +```diff +- pub fn create(_ctx: Context) -> Result<()> { +- Ok(()) +- } + ++ pub fn create(ctx: Context, message: String) -> Result<()> { ++ msg!("Create Message: {}", message); ++ let account_data = &mut ctx.accounts.message_account; ++ account_data.user = ctx.accounts.user.key(); ++ account_data.message = message; ++ account_data.bump = ctx.bumps.message_account; ++ Ok(()) ++ } +``` + + + + +Функція `create` реалізує логіку для ініціалізації даних нового акаунта +повідомлення. Вона приймає два параметри: + +1. `ctx: Context` — Надає доступ до акаунтів, зазначених у структурі + `Create`. +2. `message: String` — Повідомлення користувача, яке буде збережено. + +Тіло функції виконує наступну логіку: + +1. Виводить повідомлення у журнали програми за допомогою макроса `msg!()`. + + ```rs + msg!("Create Message: {}", message); + ``` + +2. Ініціалізація Даних Акаунта: + + - Отримує доступ до `message_account` з контексту. + + ```rs + let account_data = &mut ctx.accounts.message_account; + ``` + + - Встановлює поле `user` як публічний ключ акаунта `user`. + + ```rs + account_data.user = ctx.accounts.user.key(); + ``` + + - Встановлює поле `message` значенням аргумента `message` функції. + + ```rs + account_data.message = message; + ``` + + - Встановлює значення `bump`, використане для отримання PDA, отримане з + `ctx.bumps.message_account`. + + ```rs + account_data.bump = ctx.bumps.message_account; + ``` + + + + +Перекомпілюйте програму. + +```shell filename="Terminal" +build +``` + +### Реалізація Інструкції Update + +Далі реалізуйте інструкцію `update` для оновлення `MessageAccount` новим +повідомленням. + +Як і раніше, першим кроком є визначення акаунтів, необхідних для інструкції +`update`. + +Оновіть структуру `Update` наступним кодом: + +```rs filename="lib.rs" +#[derive(Accounts)] +#[instruction(message: String)] +pub struct Update<'info> { + #[account(mut)] + pub user: Signer<'info>, + + #[account( + mut, + seeds = [b"message", user.key().as_ref()], + bump = message_account.bump, + realloc = 8 + 32 + 4 + message.len() + 1, + realloc::payer = user, + realloc::zero = true, + )] + pub message_account: Account<'info, MessageAccount>, + pub system_program: Program<'info, System>, +} +``` + + + + +```diff +- #[derive(Accounts)] +- pub struct Update {} + ++ #[derive(Accounts)] ++ #[instruction(message: String)] ++ pub struct Update<'info> { ++ #[account(mut)] ++ pub user: Signer<'info>, ++ ++ #[account( ++ mut, ++ seeds = [b"message", user.key().as_ref()], ++ bump = message_account.bump, ++ realloc = 8 + 32 + 4 + message.len() + 1, ++ realloc::payer = user, ++ realloc::zero = true, ++ )] ++ pub message_account: Account<'info, MessageAccount>, ++ pub system_program: Program<'info, System>, ++ } +``` + + + +Структура `Update` визначає акаунти, необхідні для інструкції `update`. + +1. `user: Signer<'info>` + + - Представляє користувача, який оновлює акаунт повідомлення. + - Позначений як змінний (`#[account(mut)]`), оскільки може оплачувати + додатковий простір для `message_account`, якщо це необхідно. + - Повинен бути підписувачем для підтвердження транзакції. + +2. `message_account: Account<'info, MessageAccount>` + + - Існуючий акаунт, який зберігає повідомлення користувача і буде оновлений. + - Обмеження `mut` вказує, що дані цього акаунта будуть змінені. + - Обмеження `realloc` дозволяє змінювати розмір даних акаунта. + - Обмеження `seeds` і `bump` гарантують, що акаунт є правильним PDA. + +3. `system_program: Program<'info, System>` + + - Необхідна для можливої зміни розміру простору акаунта. + - Обмеження `realloc` викликає Системну програму для налаштування розміру + даних акаунта. + +--- + +Зверніть увагу, що обмеження `bump = message_account.bump` використовує bump +seed, який зберігається в `message_account`, замість того, щоб Anchor обчислював +його знову. + +--- + +Анотація `#[instruction(message: String)]` дозволяє структурі `Update` +отримувати доступ до параметра `message` з інструкції `update`. + + + + +Далі реалізуйте логіку для інструкції `update`. + +```rs filename="lib.rs" +pub fn update(ctx: Context, message: String) -> Result<()> { + msg!("Update Message: {}", message); + let account_data = &mut ctx.accounts.message_account; + account_data.message = message; + Ok(()) +} +``` + + + + +```diff +- pub fn update(_ctx: Context) -> Result<()> { +- Ok(()) +- } + ++ pub fn update(ctx: Context, message: String) -> Result<()> { ++ msg!("Update Message: {}", message); ++ let account_data = &mut ctx.accounts.message_account; ++ account_data.message = message; ++ Ok(()) ++ } +``` + + + +Функція `update` реалізує логіку для модифікації існуючого акаунта повідомлення. Вона приймає два параметри: + +1. `ctx: Context` — Надає доступ до акаунтів, зазначених у структурі + `Update`. +2. `message: String` — Нове повідомлення, яке замінить існуюче. + +Тіло функції виконує такі дії: + +1. Виводить повідомлення у журнали програми за допомогою макроса `msg!()`. + +2. Оновлює Дані Акаунта: + - Отримує доступ до `message_account` з контексту. + - Встановлює поле `message` як нове значення `message` із аргумента функції. + + + + +Перекомпілюйте програму. + +```shell filename="Terminal" +build +``` + +### Реалізація Інструкції Delete + +Далі реалізуйте інструкцію `delete` для закриття `MessageAccount`. + +Оновіть структуру `Delete` наступним кодом: + +```rs filename="lib.rs" +#[derive(Accounts)] +pub struct Delete<'info> { + #[account(mut)] + pub user: Signer<'info>, + + #[account( + mut, + seeds = [b"message", user.key().as_ref()], + bump = message_account.bump, + close= user, + )] + pub message_account: Account<'info, MessageAccount>, +} +``` + + + + +```diff +- #[derive(Accounts)] +- pub struct Delete {} + ++ #[derive(Accounts)] ++ pub struct Delete<'info> { ++ #[account(mut)] ++ pub user: Signer<'info>, ++ ++ #[account( ++ mut, ++ seeds = [b"message", user.key().as_ref()], ++ bump = message_account.bump, ++ close = user, ++ )] ++ pub message_account: Account<'info, MessageAccount>, ++ } +``` + + + + +Структура `Delete` визначає акаунти, необхідні для інструкції `delete`: + +1. `user: Signer<'info>` + + - Представляє користувача, який закриває акаунт повідомлення. + - Позначений як змінний (`#[account(mut)]`), оскільки він отримуватиме + лампорти з закритого акаунта. + - Повинен бути підписувачем, щоб гарантувати, що тільки відповідний + користувач може закрити свій акаунт повідомлення. + +2. `message_account: Account<'info, MessageAccount>` + + - Акаунт, який буде закритий. + - Обмеження `mut` вказує, що цей акаунт буде змінено. + - Обмеження `seeds` і `bump` гарантують, що акаунт є правильним PDA. + - Обмеження `close = user` вказує, що цей акаунт буде закритий, а його + лампорти передані в акаунт `user`. + + + + +Далі реалізуйте логіку для інструкції `delete`. + +```rs filename="lib.rs" +pub fn delete(_ctx: Context) -> Result<()> { + msg!("Delete Message"); + Ok(()) +} +``` + + + + +```diff +- pub fn delete(_ctx: Context) -> Result<()> { +- Ok(()) +- } + ++ pub fn delete(_ctx: Context) -> Result<()> { ++ msg!("Delete Message"); ++ Ok(()) ++ } +``` + + + + +Функція `delete` приймає один параметр: + +1. `_ctx: Context` — Надає доступ до акаунтів, зазначених у структурі + `Delete`. Використання `_ctx` вказує, що контекст не буде використовуватися в + тілі функції. + +Тіло функції лише виводить повідомлення у журнали програми за допомогою макроса +`msg!()`. Додаткова логіка не потрібна, оскільки фактичне закриття акаунта +виконується за допомогою обмеження `close` у структурі `Delete`. + + + + +Перекомпілюйте програму. + +```shell filename="Terminal" +build +``` + +### Розгортання Програми + +Базова CRUD-програма завершена. Розгорніть програму, виконавши команду `deploy` +у терміналі Playground. + +```shell filename="Terminal" +deploy +``` + + + + +```bash +$ deploy +Deploying... This could take a while depending on the program size and network conditions. +Deployment successful. Completed in 17s. +``` + + + + +### Налаштування Тестового Файлу + +Разом зі стартовим кодом також включений тестовий файл у `anchor.test.ts`. + +```ts filename="anchor.test.ts" +import { PublicKey } from "@solana/web3.js"; + +describe("pda", () => { + it("Create Message Account", async () => {}); + + it("Update Message Account", async () => {}); + + it("Delete Message Account", async () => {}); +}); +``` + +Додайте наведений нижче код всередину блоку `describe`, але перед секціями `it`. + +```ts filename="anchor.test.ts" +const program = pg.program; +const wallet = pg.wallet; + +const [messagePda, messageBump] = PublicKey.findProgramAddressSync( + [Buffer.from("message"), wallet.publicKey.toBuffer()], + program.programId, +); +``` + + + + +```diff + import { PublicKey } from "@solana/web3.js"; + + describe("pda", () => { ++ const program = pg.program; ++ const wallet = pg.wallet; ++ ++ const [messagePda, messageBump] = PublicKey.findProgramAddressSync( ++ [Buffer.from("message"), wallet.publicKey.toBuffer()], ++ program.programId ++ ); + + it("Create Message Account", async () => {}); + + it("Update Message Account", async () => {}); + + it("Delete Message Account", async () => {}); + }); +``` + + + + +У цьому розділі ми просто налаштовуємо тестовий файл. + +Solana Playground спрощує початкову підготовку: `pg.program` дозволяє отримати +доступ до клієнтської бібліотеки для взаємодії з програмою, а `pg.wallet` +представляє ваш гаманець у Playground. + +```ts filename="anchor.test.ts" +const program = pg.program; +const wallet = pg.wallet; +``` + +У рамках налаштування ми отримуємо PDA акаунта повідомлення. Це демонструє, як +отримати PDA у Javascript, використовуючи сіди, визначені у програмі. + +```ts filename="anchor.test.ts" +const [messagePda, messageBump] = PublicKey.findProgramAddressSync( + [Buffer.from("message"), wallet.publicKey.toBuffer()], + program.programId, +); +``` + + + + +Запустіть тестовий файл, виконавши команду `test` у терміналі Playground, щоб +переконатися, що файл працює, як очікувалося. Ми реалізуємо тести на наступних +етапах. + +```shell filename="Terminal" +test +``` + + + + +```bash +$ test +Running tests... + anchor.test.ts: + pda + ✔ Create Message Account + ✔ Update Message Account + ✔ Delete Message Account + 3 passing (4ms) +``` + + + + +### Виклик Інструкції Create + +Оновіть перший тест наступним кодом: + +```ts filename="anchor.test.ts" +it("Create Message Account", async () => { + const message = "Hello, World!"; + const transactionSignature = await program.methods + .create(message) + .accounts({ + messageAccount: messagePda, + }) + .rpc({ commitment: "confirmed" }); + + const messageAccount = await program.account.messageAccount.fetch( + messagePda, + "confirmed", + ); + + console.log(JSON.stringify(messageAccount, null, 2)); + console.log( + "Transaction Signature:", + `https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`, + ); +}); +``` + + + + +```diff +- it("Create Message Account", async () => {}); + ++ it("Create Message Account", async () => { ++ const message = "Hello, World!"; ++ const transactionSignature = await program.methods ++ .create(message) ++ .accounts({ ++ messageAccount: messagePda, ++ }) ++ .rpc({ commitment: "confirmed" }); ++ ++ const messageAccount = await program.account.messageAccount.fetch( ++ messagePda, ++ "confirmed" ++ ); ++ ++ console.log(JSON.stringify(messageAccount, null, 2)); ++ console.log( ++ "Transaction Signature:", ++ `https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana` ++ ); ++ }); +``` + + + + +Спочатку ми надсилаємо транзакцію, яка викликає інструкцію `create`, передаючи +"Hello, World!" як повідомлення. + +```ts filename="anchor.test.ts" +const message = "Hello, World!"; +const transactionSignature = await program.methods + .create(message) + .accounts({ + messageAccount: messagePda, + }) + .rpc({ commitment: "confirmed" }); +``` + +Після надсилання транзакції та створення акаунта ми отримуємо акаунт за його +адресою (`messagePda`). + +```ts filename="anchor.test.ts" +const messageAccount = await program.account.messageAccount.fetch( + messagePda, + "confirmed", +); +``` + +Нарешті, ми виводимо у журнал дані акаунта та посилання для перегляду деталей +транзакції. + +```ts filename="anchor.test.ts" +console.log(JSON.stringify(messageAccount, null, 2)); +console.log( + "Transaction Signature:", + `https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`, +); +``` + + + + +### Виклик Інструкції Update + +Оновіть другий тест наступним кодом: + +```ts filename="anchor.test.ts" +it("Update Message Account", async () => { + const message = "Hello, Solana!"; + const transactionSignature = await program.methods + .update(message) + .accounts({ + messageAccount: messagePda, + }) + .rpc({ commitment: "confirmed" }); + + const messageAccount = await program.account.messageAccount.fetch( + messagePda, + "confirmed", + ); + + console.log(JSON.stringify(messageAccount, null, 2)); + console.log( + "Transaction Signature:", + `https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`, + ); +}); +``` + + + + +```diff +- it("Update Message Account", async () => {}); + ++ it("Update Message Account", async () => { ++ const message = "Hello, Solana!"; ++ const transactionSignature = await program.methods ++ .update(message) ++ .accounts({ ++ messageAccount: messagePda, ++ }) ++ .rpc({ commitment: "confirmed" }); ++ ++ const messageAccount = await program.account.messageAccount.fetch( ++ messagePda, ++ "confirmed" ++ ); ++ ++ console.log(JSON.stringify(messageAccount, null, 2)); ++ console.log( ++ "Transaction Signature:", ++ `https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana` ++ ); ++ }); +``` + + + + +Спочатку ми надсилаємо транзакцію, яка викликає інструкцію `update`, передаючи +"Hello, Solana!" як нове повідомлення. + +```ts filename="anchor.test.ts" +const message = "Hello, Solana!"; +const transactionSignature = await program.methods + .update(message) + .accounts({ + messageAccount: messagePda, + }) + .rpc({ commitment: "confirmed" }); +``` + +Після надсилання транзакції та оновлення акаунта ми отримуємо акаунт за його +адресою (`messagePda`). + +```ts filename="anchor.test.ts" +const messageAccount = await program.account.messageAccount.fetch( + messagePda, + "confirmed", +); +``` + +Нарешті, ми виводимо у журнал дані акаунта та посилання для перегляду деталей +транзакції. + +```ts filename="anchor.test.ts" +console.log(JSON.stringify(messageAccount, null, 2)); +console.log( + "Transaction Signature:", + `https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`, +); +``` + + + + +### Виклик Інструкції Delete + +Оновіть третій тест наступним кодом: + +```ts filename="anchor.test.ts" +it("Delete Message Account", async () => { + const transactionSignature = await program.methods + .delete() + .accounts({ + messageAccount: messagePda, + }) + .rpc({ commitment: "confirmed" }); + + const messageAccount = await program.account.messageAccount.fetchNullable( + messagePda, + "confirmed", + ); + + console.log("Expect Null:", JSON.stringify(messageAccount, null, 2)); + console.log( + "Transaction Signature:", + `https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`, + ); +}); +``` + + + + +```diff +- it("Delete Message Account", async () => {}); + ++ it("Delete Message Account", async () => { ++ const transactionSignature = await program.methods ++ .delete() ++ .accounts({ ++ messageAccount: messagePda, ++ }) ++ .rpc({ commitment: "confirmed" }); ++ ++ const messageAccount = await program.account.messageAccount.fetchNullable( ++ messagePda, ++ "confirmed" ++ ); ++ ++ console.log("Expect Null:", JSON.stringify(messageAccount, null, 2)); ++ console.log( ++ "Transaction Signature:", ++ `https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana` ++ ); ++ }); +``` + + + + +Спочатку ми надсилаємо транзакцію, яка викликає інструкцію `delete` для закриття +акаунта повідомлення. + +```ts filename="anchor.test.ts" +const transactionSignature = await program.methods + .delete() + .accounts({ + messageAccount: messagePda, + }) + .rpc({ commitment: "confirmed" }); +``` + +Після надсилання транзакції та закриття акаунта ми намагаємося отримати акаунт +за його адресою (`messagePda`), використовуючи `fetchNullable`, оскільки ми +очікуємо, що результат буде `null`, тому що акаунт закритий. + +```ts filename="anchor.test.ts" +const messageAccount = await program.account.messageAccount.fetchNullable( + messagePda, + "confirmed", +); +``` + +Нарешті, ми виводимо у журнал дані акаунта та посилання для перегляду деталей +транзакції, де дані акаунта повинні бути відображені як `null`. + +```ts filename="anchor.test.ts" +console.log(JSON.stringify(messageAccount, null, 2)); +console.log( + "Transaction Signature:", + `https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`, +); +``` + + + + +### Запуск Тестів + +Після налаштування тестів запустіть тестовий файл, виконавши команду `test` у +терміналі Playground. + +```shell filename="Terminal" +test +``` + + + + +```bash +$ test +Running tests... + anchor.test.ts: + pda + { + "user": "3z9vL1zjN6qyAFHhHQdWYRTFAcy69pJydkZmSFBKHg1R", + "message": "Hello, World!", + "bump": 254 +} + Transaction Signature: https://solana.fm/tx/5oBT4jEdUR6CRYsFNGoqvyMBTRDvFqRWTAAmCGM9rEvYRBWy3B2bkb6GVFpVPKBnkr714UCFUurBSDKSa7nLHo8e?cluster=devnet-solana + ✔ Create Message Account (1025ms) + { + "user": "3z9vL1zjN6qyAFHhHQdWYRTFAcy69pJydkZmSFBKHg1R", + "message": "Hello, Solana!", + "bump": 254 +} + Transaction Signature: https://solana.fm/tx/42veGAsQjHbJP1SxWBGcfYF7EdRN9X7bACNv23NSZNe4U7w2dmaYgSv8UUWXYzwgJPoNHejhtWdKZModHiMaTWYK?cluster=devnet-solana + ✔ Update Message Account (713ms) + Expect Null: null + Transaction Signature: https://solana.fm/tx/Sseog2i2X7uDEn2DyDMMJKVHeZEzmuhnqUwicwGhnGhstZo8URNwUZgED8o6HANiojJkfQbhXVbGNLdhsFtWrd6?cluster=devnet-solana + ✔ Delete Message Account (812ms) + 3 passing (3s) +``` + + + + + diff --git a/docs/locales/uk/intro/quick-start/reading-from-network.md b/docs/locales/uk/intro/quick-start/reading-from-network.md new file mode 100644 index 000000000..e7dd00e7f --- /dev/null +++ b/docs/locales/uk/intro/quick-start/reading-from-network.md @@ -0,0 +1,401 @@ +--- +sidebarLabel: Читання з Мережі +title: Читання з Мережі +sidebarSortOrder: 1 +description: + Дізнайтеся, як зчитувати дані з блокчейн-мережі Solana. Цей посібник охоплює + отримання акаунтів гаманців, програмних акаунтів і акаунтів випуску токенів за + допомогою JavaScript/TypeScript із практичними прикладами на основі бібліотеки + Solana web3.js. +--- + +Давайте розглянемо, як зчитувати дані з мережі Solana. Ми отримаємо кілька +різних акаунтів, щоб зрозуміти структуру акаунта Solana. + +У Solana всі дані містяться у так званих "акаунтах". Ви можете думати про дані в +Solana як про загальнодоступну базу даних із єдиною таблицею "Accounts", де +кожен запис у цій таблиці є окремим акаунтом. + +Акаунти Solana можуть містити "стан" або виконувані програми, які можна +розглядати як записи в одній таблиці "Accounts". Кожен акаунт має "адресу" +(публічний ключ), яка є унікальним ідентифікатором для доступу до відповідних +даних у блокчейні. + +Акаунти Solana можуть містити: + +- **Стан**: Дані, які призначені для зчитування і зберігання. Це може бути + інформація про токени, дані користувачів або будь-які інші дані, визначені у + програмі. +- **Виконувані програми**: Акаунти, які містять фактичний код програм Solana. + Вони включають інструкції, які можна виконувати у мережі. + +Цей поділ програмного коду та стану програми є ключовою особливістю Моделі +Акаунтів Solana. Для отримання додаткової інформації відвідайте сторінку +[Модель Акаунтів Solana](/docs/uk/core/accounts). + +## Отримання Гаманця Playground + +Почнемо з розгляду знайомого акаунта — вашого власного гаманця Playground! Ми +отримаємо цей акаунт і розглянемо його структуру, щоб зрозуміти, як виглядає +базовий акаунт Solana. + + + +### Відкриття Прикладу 1 + +Натисніть це [посилання](https://beta.solpg.io/6671c5e5cffcf4b13384d198), щоб +відкрити приклад у Solana Playground. Ви побачите такий код: + +```ts filename="client.ts" +const address = pg.wallet.publicKey; +const accountInfo = await pg.connection.getAccountInfo(address); + +console.log(JSON.stringify(accountInfo, null, 2)); +``` + + + + +Цей код виконує три прості дії: + +- Отримує адресу вашого гаманця Playground: + + ```ts + const address = pg.wallet.publicKey; + ``` + +- Отримує `AccountInfo` для акаунта за цією адресою: + + ```ts + const accountInfo = await pg.connection.getAccountInfo(address); + ``` + +- Виводить `AccountInfo` у термінал Playground: + + ```ts + console.log(JSON.stringify(accountInfo, null, 2)); + ``` + + + + +### Запуск Прикладу 1 + +У терміналі Playground введіть команду `run` і натисніть Enter: + +```shell filename="Terminal" +run +``` + +Ви повинні побачити деталі вашого акаунта гаманця, включаючи його баланс у +лампортах, із результатом, схожим на наступний: + + + + +```shell filename="Terminal" +$ run +Running client... + client.ts: + { + "data": { + "type": "Buffer", + "data": [] + }, + "executable": false, + "lamports": 5000000000, + "owner": "11111111111111111111111111111111", + "rentEpoch": 18446744073709552000, + "space": 0 +} +``` + + + + +Ваш гаманець насправді є лише акаунтом, яким керує Системна програма. Основна +мета акаунта гаманця — зберігати баланс SOL (значення у полі `lamports`). + +--- + +В основі всі акаунти Solana представлені у стандартному форматі, який +називається `AccountInfo`. Тип даних +[AccountInfo](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/sdk/program/src/account_info.rs#L19-L36) +є базовою структурою даних для всіх акаунтів Solana. + +Розберемо поля у виведених даних: + +- `data` — Це поле містить те, що ми зазвичай називаємо "даними" акаунта. Для + гаманця воно порожнє (0 байтів), але інші акаунти використовують це поле для + зберігання будь-яких довільних даних у вигляді серіалізованого буфера байтів. + +> Коли дані "буферизуються" таким чином, вони зберігають свою цілісність і +> можуть пізніше бути десеріалізовані назад у свій початковий вигляд для +> використання у програмах. Цей процес широко використовується в блокчейні для +> ефективної обробки даних. + +- `executable` — Прапорець, який вказує, чи є акаунт виконуваною програмою. Для + гаманців та будь-яких акаунтів, які зберігають стан, значення `false`. +- `owner` — Це поле показує, яка програма контролює акаунт. Для гаманців це + завжди Системна програма з адресою `11111111111111111111111111111111`. +- `lamports` — Баланс акаунта у лампортах (1 SOL = 1,000,000,000 лампортів). +- `rentEpoch` — Поле, пов’язане зі старим механізмом збору оренди Solana (наразі + не використовується). +- `space` — Вказує ємність (довжину) поля `data`, але не є полем типу + `AccountInfo`. + + + + + + +## Отримання Програми Token Program + +Далі ми розглянемо програму Token Extensions, яка є виконуваною програмою для +взаємодії з токенами на Solana. + + + +### Відкриття Прикладу 2 + +Натисніть це [посилання](https://beta.solpg.io/6671c6e7cffcf4b13384d199), щоб +відкрити приклад у Solana Playground. Ви побачите такий код: + +```ts filename="client.ts" {3} +import { PublicKey } from "@solana/web3.js"; + +const address = new PublicKey("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"); +const accountInfo = await pg.connection.getAccountInfo(address); + +console.log(JSON.stringify(accountInfo, null, 2)); +``` + +Замість отримання вашого гаманця Playground, тут ми отримуємо адресу акаунта +програми Token Extensions. + +### Запуск Прикладу 2 + +Запустіть код, виконавши команду `run` у терміналі. + +```shell filename="Terminal" +run +``` + +Ознайомтеся з виведеними даними та тим, чим цей акаунт програми відрізняється +від вашого акаунта гаманця. + + + + +```shell filename="Terminal" {15, 17} +$ run +Running client... + client.ts: + { + "data": { + "type": "Buffer", + "data": [ + 2, + 0, + //... additional bytes + 86, + 51 + ] + }, + "executable": true, + "lamports": 1141440, + "owner": "BPFLoaderUpgradeab1e11111111111111111111111", + "rentEpoch": 18446744073709552000, + "space": 36 +} +``` + + + + +Програма Token Extensions є виконуваним акаунтом програми, але має таку ж +структуру `AccountInfo`. + +Основні відмінності в `AccountInfo`: + +- **`executable`** — Встановлено у `true`, що вказує на те, що цей акаунт є + виконуваною програмою. +- **`data`** — Містить серіалізовані дані (на відміну від порожніх даних у + акаунті гаманця). Дані для акаунта програми зберігають адресу іншого акаунта + (Program Executable Data Account), який містить байт-код програми. +- **`owner`** — Акаунт належить завантажувачу Upgradable BPF Loader + (`BPFLoaderUpgradeab1e11111111111111111111111`), спеціальній програмі, яка + управляє виконуваними акаунтами. + +--- + +Ви можете перевірити Solana Explorer для +[акаунта програми Token Extensions](https://explorer.solana.com/address/TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb) +та його відповідного +[Program Executable Data Account](https://explorer.solana.com/address/DoU57AYuPFu2QU514RktNPG22QhApEjnKxnBcu4BHDTY). + +Program Executable Data Account містить скомпільований байт-код програми Token +Extensions +[вихідний код](https://github.com/solana-labs/solana-program-library/tree/b1c44c171bc95e6ee74af12365cb9cbab68be76c/token/program-2022/src). + + + + + + +## Отримання Акаунта Mint + +На цьому етапі ми розглянемо акаунт Mint, який представляє унікальний токен у +мережі Solana. + + + +### Відкриття Прикладу 3 + +Натисніть це [посилання](https://beta.solpg.io/6671c9aecffcf4b13384d19a), щоб +відкрити приклад у Solana Playground. Ви побачите такий код: + +```ts filename="client.ts" {3} +import { PublicKey } from "@solana/web3.js"; + +const address = new PublicKey("C33qt1dZGZSsqTrHdtLKXPZNoxs6U1ZBfyDkzmj6mXeR"); +const accountInfo = await pg.connection.getAccountInfo(address); + +console.log(JSON.stringify(accountInfo, null, 2)); +``` + +У цьому прикладі ми отримаємо адресу існуючого акаунта Mint у devnet. + +### Запуск Прикладу 3 + +Запустіть код, виконавши команду `run`. + +```shell filename="Terminal" +run +``` + + + + +```shell filename="Terminal" {17} +$ run +Running client... + client.ts: + { + "data": { + "type": "Buffer", + "data": [ + 1, + 0, + //... additional bytes + 0, + 0 + ] + }, + "executable": false, + "lamports": 4176000, + "owner": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb", + "rentEpoch": 18446744073709552000, + "space": 430 +} +``` + + + + +Основні відмінності в `AccountInfo`: + +- **`owner`** — Акаунт mint належить програмі Token Extensions + (`TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`). +- **`executable`** — Встановлено у `false`, оскільки цей акаунт зберігає стан, а + не виконуваний код. +- **`data`** — Містить серіалізовані дані про токен (авторитет випуску, загальну + кількість, кількість знаків після коми тощо). + + + + +### Десеріалізація Даних Акаунта Mint + +Щоб зчитати поле `data` з будь-якого акаунта, потрібно десеріалізувати буфер +даних у очікуваний тип даних. Це часто виконується за допомогою допоміжних +функцій клієнтських бібліотек для конкретної програми. + +**Десеріалізація** — це процес перетворення даних зі збереженого формату +(наприклад, необроблених байтів або JSON) назад у використовуваний +структурований формат у програмі. У блокчейні це включає взяття необроблених, +закодованих даних із мережі та їх перетворення назад в об'єкти, класи або +читабельні структури, щоб розробники могли отримати доступ до конкретної +інформації та маніпулювати нею у програмі. Десеріалізація є важливою для +інтерпретації даних акаунтів або транзакцій, отриманих із мережі, у формі, яку +програма може обробляти і відображати осмислено. + +Відкрийте цей [приклад](https://beta.solpg.io/6671cd8acffcf4b13384d19b) у Solana +Playground. Ви побачите такий код: + +```ts filename="client.ts" +import { PublicKey } from "@solana/web3.js"; +import { getMint, TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; + +const address = new PublicKey("C33qt1dZGZSsqTrHdtLKXPZNoxs6U1ZBfyDkzmj6mXeR"); +const mintData = await getMint( + pg.connection, + address, + "confirmed", + TOKEN_2022_PROGRAM_ID, +); + +console.log(mintData); +``` + +Цей приклад використовує функцію `getMint`, яка автоматично десеріалізує поле +`data` акаунта Mint. + +Запустіть код, виконавши команду `run`. + +```shell filename="Terminal" +run +``` + +Ви повинні побачити наступні десеріалізовані дані акаунта Mint. + + + + +```shell filename="Terminal" +Running client... + client.ts: + { address: { _bn: { negative: 0, words: [Object], length: 10, red: null } }, + mintAuthority: { _bn: { negative: 0, words: [Object], length: 10, red: null } }, + supply: {}, + decimals: 2, + isInitialized: true, + freezeAuthority: null, + tlvData: } +``` + + + + +Функція `getMint` десеріалізує дані акаунта у тип даних +[Mint](https://github.com/solana-labs/solana-program-library/blob/b1c44c171bc95e6ee74af12365cb9cbab68be76c/token/program/src/state.rs#L18-L32), +визначений у вихідному коді програми Token Extensions. + +- **`address`** — Адреса акаунта Mint. +- **`mintAuthority`** — Авторитет, який може випускати нові токени. +- **`supply`** — Загальна кількість токенів в обігу. +- **`decimals`** — Кількість десяткових знаків для токена. +- **`isInitialized`** — Чи були дані Mint ініціалізовані. +- **`freezeAuthority`** — Авторитет, який має право заморожувати акаунти + токенів. +- **`tlvData`** — Додаткові дані для Token Extensions (вимагають подальшої + десеріалізації). + +Ви можете переглянути повністю десеріалізовані +[дані акаунта Mint](https://explorer.solana.com/address/C33qt1dZGZSsqTrHdtLKXPZNoxs6U1ZBfyDkzmj6mXeR?cluster=devnet), +включаючи активовані Token Extensions, у Solana Explorer. + + + + + diff --git a/docs/locales/uk/intro/quick-start/writing-to-network.md b/docs/locales/uk/intro/quick-start/writing-to-network.md new file mode 100644 index 000000000..37bbbc4bf --- /dev/null +++ b/docs/locales/uk/intro/quick-start/writing-to-network.md @@ -0,0 +1,367 @@ +--- +sidebarLabel: Запис у Мережу +title: Запис у Мережу +sidebarSortOrder: 2 +description: + Дізнайтеся, як взаємодіяти з мережею Solana шляхом надсилання транзакцій та + інструкцій. Слідуйте покроковим прикладам для переказу токенів SOL та + створення нових токенів за допомогою System Program та Token Extensions + Program. +--- + +Тепер, коли ми розглянули зчитування даних із мережі Solana, давайте навчимося +записувати дані до неї. У Solana взаємодія з мережею здійснюється шляхом +надсилання транзакцій, що складаються з інструкцій. Ці інструкції визначаються +програмами, які містять бізнес-логіку про те, як мають оновлюватися акаунти. + +Розглянемо два поширені операції, переказ SOL і створення токена, щоб +продемонструвати, як створювати і надсилати транзакції. Для отримання додаткової +інформації відвідайте сторінки +[Транзакції та Інструкції](/docs/uk/core/transactions) і +[Комісії у Solana](/docs/uk/core/fees). + +## Переказ SOL + +Почнемо із простої операції переказу SOL з вашого гаманця на інший акаунт. Це +вимагає виклику інструкції переказу у System Program. + + + +### Відкриття Прикладу 1 + +Натисніть це [посилання](https://beta.solpg.io/6671d85ecffcf4b13384d19e), щоб +відкрити приклад у Solana Playground. Ви побачите такий код: + +```ts filename="client.ts" +import { + LAMPORTS_PER_SOL, + SystemProgram, + Transaction, + sendAndConfirmTransaction, + Keypair, +} from "@solana/web3.js"; + +const sender = pg.wallet.keypair; +const receiver = new Keypair(); + +const transferInstruction = SystemProgram.transfer({ + fromPubkey: sender.publicKey, + toPubkey: receiver.publicKey, + lamports: 0.01 * LAMPORTS_PER_SOL, +}); + +const transaction = new Transaction().add(transferInstruction); + +const transactionSignature = await sendAndConfirmTransaction( + pg.connection, + transaction, + [sender], +); + +console.log( + "Transaction Signature:", + `https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`, +); +``` + + + + +Цей скрипт виконує наступні дії: + +- Встановлює ваш гаманець Playground як відправника: + + ```ts + const sender = pg.wallet.keypair; + ``` + +- Створює нову ключову пару як отримувача: + + ```ts + const receiver = new Keypair(); + ``` + +- Створює інструкцію переказу для переказу 0.01 SOL: + + ```ts + const transferInstruction = SystemProgram.transfer({ + fromPubkey: sender.publicKey, + toPubkey: receiver.publicKey, + lamports: 0.01 * LAMPORTS_PER_SOL, + }); + ``` + +- Формує транзакцію, включаючи інструкцію переказу: + + ```ts + const transaction = new Transaction().add(transferInstruction); + ``` + +- Відправляє та підтверджує транзакцію: + + ```ts + const transactionSignature = await sendAndConfirmTransaction( + pg.connection, + transaction, + [sender], + ); + ``` + +- Виводить посилання на SolanaFM у термінал Playground для перегляду деталей + транзакції. + + ```ts + console.log( + "Transaction Signature:", + `https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`, + ); + ``` + + + + +### Запуск Прикладу 1 + +Запустіть код, виконавши команду `run`. + +```shell filename="Terminal" +run +``` + +Натисніть на посилання у виведених даних, щоб переглянути деталі транзакції у +SolanaFM Explorer. + + + + +```shell filename="Terminal" +Running client... + client.ts: + Transaction Signature: https://solana.fm/tx/he9dBwrEPhrfrx2BaX4cUmUbY22DEyqZ837zrGrFRnYEBmKhCb5SvoaUeRKSeLFXiGxC8hFY5eDbHqSJ7NYYo42?cluster=devnet-solana +``` + + + + +![Transfer SOL](/assets/docs/intro/quickstart/transfer-sol.png) + +Ви щойно надіслали свою першу транзакцію у Solana! Зверніть увагу, як ми +створили інструкцію, додали її до транзакції, а потім відправили цю транзакцію +до мережі. Це базовий процес для створення будь-якої транзакції. + + + +## Створення Токена + +Тепер створимо новий токен шляхом створення та ініціалізації акаунта Mint. Для +цього потрібні дві інструкції: + +- Виклик System Program для створення нового акаунта. +- Виклик Token Extensions Program для ініціалізації даних акаунта. + + + +### Відкриття Прикладу 2 + +Натисніть це [посилання](https://beta.solpg.io/6671da4dcffcf4b13384d19f), щоб +відкрити приклад у Solana Playground. Ви побачите наступний код: + +```ts filename="client.ts" +import { + Connection, + Keypair, + SystemProgram, + Transaction, + clusterApiUrl, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { + MINT_SIZE, + TOKEN_2022_PROGRAM_ID, + createInitializeMint2Instruction, + getMinimumBalanceForRentExemptMint, +} from "@solana/spl-token"; + +const wallet = pg.wallet; +const connection = new Connection(clusterApiUrl("devnet"), "confirmed"); + +// Generate keypair to use as address of mint account +const mint = new Keypair(); + +// Calculate minimum lamports for space required by mint account +const rentLamports = await getMinimumBalanceForRentExemptMint(connection); + +// Instruction to create new account with space for new mint account +const createAccountInstruction = SystemProgram.createAccount({ + fromPubkey: wallet.publicKey, + newAccountPubkey: mint.publicKey, + space: MINT_SIZE, + lamports: rentLamports, + programId: TOKEN_2022_PROGRAM_ID, +}); + +// Instruction to initialize mint account +const initializeMintInstruction = createInitializeMint2Instruction( + mint.publicKey, + 2, // decimals + wallet.publicKey, // mint authority + wallet.publicKey, // freeze authority + TOKEN_2022_PROGRAM_ID, +); + +// Build transaction with instructions to create new account and initialize mint account +const transaction = new Transaction().add( + createAccountInstruction, + initializeMintInstruction, +); + +const transactionSignature = await sendAndConfirmTransaction( + connection, + transaction, + [ + wallet.keypair, // payer + mint, // mint address keypair + ], +); + +console.log( + "\nTransaction Signature:", + `https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`, +); + +console.log( + "\nMint Account:", + `https://solana.fm/address/${mint.publicKey}?cluster=devnet-solana`, +); +``` + + + + +Цей скрипт виконує наступні кроки: + +- Налаштовує ваш гаманець Playground і з'єднання з devnet Solana: + + ```ts + const wallet = pg.wallet; + const connection = new Connection(clusterApiUrl("devnet"), "confirmed"); + ``` + +- Генерує нову ключову пару для акаунта mint: + + ```ts + const mint = new Keypair(); + ``` + +- Розраховує мінімальну кількість лампортів, необхідну для акаунта Mint: + + ```ts + const rentLamports = await getMinimumBalanceForRentExemptMint(connection); + ``` + +- Створює інструкцію для створення нового акаунта mint, вказуючи програму Token + Extensions (TOKEN_2022_PROGRAM_ID) як власника нового акаунта: + + ```ts + const createAccountInstruction = SystemProgram.createAccount({ + fromPubkey: wallet.publicKey, + newAccountPubkey: mint.publicKey, + space: MINT_SIZE, + lamports: rentLamports, + programId: TOKEN_2022_PROGRAM_ID, + }); + ``` + +- Створює інструкцію для ініціалізації даних акаунта mint: + + ```ts + const initializeMintInstruction = createInitializeMint2Instruction( + mint.publicKey, + 2, + wallet.publicKey, + wallet.publicKey, + TOKEN_2022_PROGRAM_ID, + ); + ``` + +- Додає обидві інструкції до однієї транзакції: + + ```ts + const transaction = new Transaction().add( + createAccountInstruction, + initializeMintInstruction, + ); + ``` + +- Відправляє та підтверджує транзакцію. Гаманець і ключова пара mint передаються + як підписувачі транзакції. Гаманець потрібен для оплати створення нового + акаунта, а ключова пара mint потрібна, оскільки її публічний ключ + використовується як адреса нового акаунта: + + ```ts + const transactionSignature = await sendAndConfirmTransaction( + connection, + transaction, + [wallet.keypair, mint], + ); + ``` + +- Виводить посилання для перегляду транзакції та деталей акаунта mint на + SolanaFM: + + ```ts + console.log( + "\nTransaction Signature:", + `https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`, + ); + + console.log( + "\nMint Account:", + `https://solana.fm/address/${mint.publicKey}?cluster=devnet-solana`, + ); + ``` + + + + +### Запуск Прикладу 2 + +Запустіть код, виконавши команду `run`. + +```shell filename="Terminal" +run +``` + +Ви побачите два посилання, виведених у термінал Playground: + +- Одне для деталей транзакції +- Інше для новоствореного акаунта mint + +Натисніть на посилання, щоб переглянути деталі транзакції та новостворений +акаунт mint у SolanaFM. + + + + +```shell filename="Terminal" +Running client... + client.ts: + +Transaction Signature: https://solana.fm/tx/3BEjFxqyGwHXWSrEBnc7vTSaXUGDJFY1Zr6L9iwLrjH8KBZdJSucoMrFUEJgWrWVRYzrFvbjX8TmxKUV88oKr86g?cluster=devnet-solana + +Mint Account: https://solana.fm/address/CoZ3Nz488rmATDhy1hPk5fvwSZaipCngvf8rYBYVc4jN?cluster=devnet-solana +``` + + + + +![Create Token](/assets/docs/intro/quickstart/create-token.png) + +![Mint Account](/assets/docs/intro/quickstart/mint-account.png) + +Зверніть увагу, як цього разу ми створили транзакцію з кількома інструкціями. +Спочатку ми створили новий акаунт, а потім ініціалізували його дані як mint. +Таким чином створюються складніші транзакції, які включають інструкції з кількох +програм. + + diff --git a/docs/locales/uk/intro/wallets.md b/docs/locales/uk/intro/wallets.md new file mode 100644 index 000000000..e3af2e607 --- /dev/null +++ b/docs/locales/uk/intro/wallets.md @@ -0,0 +1,70 @@ +--- +sidebarLabel: Гаманці +title: Посібник із Гаманців Solana +sidebarSortOrder: 3 +--- + +Цей документ описує різні варіанти гаманців, доступних користувачам Solana, які +хочуть надсилати, отримувати та взаємодіяти з токенами SOL у блокчейні Solana. + +## Що таке Гаманець? + +Криптогаманець — це пристрій або програма, яка зберігає набір ключів і може +використовуватися для надсилання, отримання та відстеження володіння +криптовалютами. Гаманці можуть мати різні форми. Гаманець може бути каталогом +або файлом у файловій системі вашого комп’ютера, аркушем паперу або +спеціалізованим пристроєм, який називається _апаратний гаманець_. Також існують +різні програми для смартфонів і комп’ютерів, які надають зручний спосіб +створення та управління гаманцями. + +### Keypair + +[_Keypair_](/docs/uk/terminology.md#keypair) — це безпечно згенерований +[_секретний ключ_](#secret-key) і його криптографічно виведений +[_публічний ключ_](#public-key). Секретний ключ та його відповідний публічний +ключ разом називаються _ключовою парою_. Гаманець містить колекцію однієї або +кількох ключових пар і надає засоби для взаємодії з ними. + +### Публічний ключ + +[_Публічний ключ_](/docs/uk/terminology.md#public-key-pubkey) (часто +скорочується до _pubkey_) відомий як _адреса для отримання_ гаманця або просто +його _адреса_. Адресу гаманця **можна вільно передавати та показувати**. Коли +інша сторона збирається надіслати певну кількість криптовалюти на гаманець, їй +потрібно знати адресу для отримання. Залежно від реалізації блокчейну, адреса +також може використовуватися для перегляду певної інформації про гаманець, +наприклад, балансу, але вона не дозволяє змінювати гаманець або знімати з нього +токени. + +### Секретний ключ + +[_Секретний ключ_](/docs/uk/terminology.md#private-key) (також називається +_приватним ключем_) потрібен для цифрового підпису будь-яких транзакцій для +відправлення криптовалюти на іншу адресу або внесення змін до гаманця. Секретний +ключ **ніколи не повинен бути переданий іншим**. Якщо хтось отримає доступ до +секретного ключа гаманця, він може зняти всі токени, які він містить. Якщо +секретний ключ гаманця втрачено, будь-які токени, відправлені на адресу цього +гаманця, **назавжди втрачені**. + +## Безпека + +Різні рішення для гаманців пропонують різні підходи до безпеки ключової пари, +взаємодії з нею та підписання транзакцій для використання/витрачання токенів. +Деякі є простішими у використанні, ніж інші. Деякі забезпечують більш безпечне +зберігання та резервне копіювання секретних ключів. Solana підтримує кілька +типів гаманців, тому ви можете обрати правильний баланс між безпекою та +зручністю. + +**Якщо ви хочете отримувати токени SOL у блокчейні Solana, вам спочатку потрібно +створити гаманець.** + +## Підтримувані Гаманці + +Кілька гаманців на основі браузера та мобільних додатків підтримують Solana. +Знайдіть варіанти, які можуть підійти вам, на сторінці +[Solana Wallets](https://solana.com/wallets). + +Для досвідчених користувачів або розробників більше підходять +[гаманці командного рядка](https://docs.anza.xyz/cli/wallets), оскільки нові +функції в блокчейні Solana завжди спочатку підтримуються в командному рядку, +перш ніж бути інтегрованими у сторонні рішення. diff --git a/docs/locales/uk/more/exchange.md b/docs/locales/uk/more/exchange.md new file mode 100644 index 000000000..9958a67a3 --- /dev/null +++ b/docs/locales/uk/more/exchange.md @@ -0,0 +1,1286 @@ +--- +title: Додати Solana на Вашу Біржу +--- + +Цей посібник описує, як додати нативний токен Solana (SOL) до вашої +криптовалютної біржі. + +## Налаштування Ноди + +Ми наполегливо рекомендуємо налаштувати щонайменше дві ноди на +високопродуктивних комп’ютерах або хмарних інстанціях, своєчасно оновлювати їх +до нових версій і відстежувати роботу сервісу за допомогою вбудованих +інструментів моніторингу. + +Це налаштування дозволяє вам: + +- мати самостійно керований шлюз до кластеру Solana mainnet-beta для отримання + даних і надсилання транзакцій на виведення +- мати повний контроль над тим, скільки історичних даних блоків зберігається +- забезпечувати доступність вашого сервісу навіть у разі відмови однієї з нод + +Ноди Solana вимагають відносно високої обчислювальної потужності для обробки +швидких блоків і високої пропускної здатності (TPS). Для конкретних вимог +дивіться +[рекомендації щодо апаратного забезпечення](https://docs.anza.xyz/operations/requirements). + +Щоб запустити ноду API: + +1. [Встановіть набір інструментів командного рядка Solana](/docs/uk/intro/installation.md) +2. Запустіть валідатор щонайменше з наступними параметрами: + +```shell +solana-validator \ + --ledger \ + --identity \ + --entrypoint \ + --expected-genesis-hash \ + --rpc-port 8899 \ + --no-voting \ + --enable-rpc-transaction-history \ + --limit-ledger-size \ + --known-validator \ + --only-known-rpc +``` + +Налаштуйте параметр `--ledger` для бажаного розташування зберігання леджера та +параметр `--rpc-port` для порту, який ви хочете зробити доступним. + +Параметри `--entrypoint` та `--expected-genesis-hash` є специфічними для +кластера, до якого ви приєднуєтеся. +[Поточні параметри для Mainnet Beta](https://docs.anza.xyz/clusters/available#example-solana-validator-command-line-2) + +Параметр `--limit-ledger-size` дозволяє вказати, скільки +[шредів](/docs/uk/terminology.md#shred) леджера ваша нода зберігатиме на диску. +Якщо цей параметр не вказано, валідатор зберігатиме весь леджер, доки не +закінчиться місце на диску. Значення за замовчуванням намагається обмежити +використання місця на диску леджером до 500 ГБ. За потреби можна змінити це +значення, додавши аргумент до параметра `--limit-ledger-size`. Для перегляду +значення за замовчуванням, яке використовується параметром +`--limit-ledger-size`, виконайте команду `solana-validator --help`. Більше +інформації про вибір власного значення обмеження можна знайти +[тут](https://github.com/solana-labs/solana/blob/583cec922b6107e0f85c7e14cb5e642bc7dfb340/core/src/ledger_cleanup_service.rs#L15-L26). + +Вказівка одного або кількох параметрів `--known-validator` може захистити вас +від запуску з підробленого знімку. +[Більше про цінність запуску з відомими валідаторами](https://docs.anza.xyz/operations/guides/validator-start#known-validators) + +Додаткові параметри, які варто розглянути: + +- `--private-rpc` забороняє публікацію вашого RPC-порту для використання іншими + нодами +- `--rpc-bind-address` дозволяє вказати іншу IP-адресу для прив’язки RPC-порту + +### Автоматичний Перезапуск та Моніторинг + +Ми рекомендуємо налаштувати кожну з ваших нод на автоматичний перезапуск після +завершення роботи, щоб мінімізувати втрату даних. Запуск програмного +забезпечення Solana як служби systemd є одним із чудових варіантів. + +Для моніторингу ми надаємо інструмент +[`solana-watchtower`](https://github.com/solana-labs/solana/blob/master/watchtower/README.md), +який може моніторити ваш валідатор і визначати, чи є процес `solana-validator` +несправним. Він може бути налаштований для сповіщень через Slack, Telegram, +Discord або Twilio. Для деталей виконайте команду `solana-watchtower --help`. + +```shell +solana-watchtower --validator-identity +``` + +> Додаткову інформацію про +> [найкращі практики для Solana Watchtower](https://docs.anza.xyz/operations/best-practices/monitoring#solana-watchtower) +> можна знайти у документації. + +#### Оголошення про Нові Релізи ПЗ + +Ми випускаємо нове програмне забезпечення часто (приблизно один реліз на +тиждень). Іноді нові версії містять несумісні протокольні зміни, які вимагають +своєчасного оновлення ПЗ, щоб уникнути помилок при обробці блоків. + +Наші офіційні оголошення про всі види релізів (звичайні та пов’язані з безпекою) +публікуються в [каналі Discord](https://solana.com/discord) під назвою +`#mb-announcement` (`mb` означає `mainnet-beta`). + +Як і для валідаторів зі ставками, ми очікуємо, що валідатори, які обслуговуються +біржами, будуть оновлюватися протягом одного-двох робочих днів після оголошення +про звичайний реліз. Для релізів, пов’язаних із безпекою, може знадобитися більш +термінове реагування. + +### Цілісність Леджера + +За замовчуванням кожна з ваших нод завантажується зі знімку, наданого одним із +ваших відомих валідаторів. Цей знімок відображає поточний стан ланцюга, але не +містить повного історичного леджера. Якщо одна з ваших нод зупиняється та +завантажується з нового знімка, у леджері цієї ноди може з’явитися прогалина. +Щоб уникнути цієї проблеми, додайте параметр `--no-snapshot-fetch` до команди +`solana-validator`, щоб отримувати історичні дані леджера замість знімка. + +Не додавайте параметр `--no-snapshot-fetch` під час початкового завантаження, +оскільки неможливо завантажити ноду від самого генезис-блоку. Спочатку +завантажтеся зі знімка, а потім додайте параметр `--no-snapshot-fetch` для +наступних перезавантажень. + +Варто зазначити, що обсяг доступного історичного леджера від інших нод у мережі +обмежений. Якщо ваші валідатори зазнають значних простоїв, вони можуть не змогти +синхронізуватися з мережею і будуть змушені завантажити новий знімок від +відомого валідатора, що створить прогалину в історичному леджері, яку неможливо +заповнити. + +### Мінімізація Доступу до Портів Валідатора + +Валідатору необхідно, щоб різні UDP- і TCP-порти були відкриті для вхідного +трафіку від усіх інших валідаторів Solana. Хоча це найефективніший режим роботи +і настійно рекомендується, можливо обмежити валідатор лише для вхідного трафіку +від одного іншого валідатора Solana. + +Спочатку додайте аргумент `--restricted-repair-only-mode`. Це призведе до роботи +валідатора в обмеженому режимі, в якому він не отримуватиме push-повідомлення +від інших валідаторів і замість цього постійно опитуватиме інші валідатори для +отримання блоків. Валідатор буде передавати UDP-пакети іншим валідаторам лише +через порти _Gossip_ та _ServeR_ ("serve repair") і отримуватиме UDP-пакети лише +через порти _Gossip_ та _Repair_. + +Порт _Gossip_ є двостороннім і дозволяє вашому валідатору підтримувати зв’язок +із рештою кластеру. Ваш валідатор передаватиме запити на ремонт через порт +_ServeR_, щоб отримувати нові блоки від решти мережі, оскільки Turbine тепер +відключено. Ваш валідатор отримуватиме відповіді на запити ремонту через порт +_Repair_ від інших валідаторів. + +Щоб додатково обмежити валідатор для запитів блоків лише від одного або кількох +валідаторів, спочатку визначте публічний ключ (pubkey) цього валідатора та +додайте аргументи `--gossip-pull-validator PUBKEY --repair-validator PUBKEY` для +кожного PUBKEY. Це створить навантаження на кожен валідатор, який ви додаєте, +тому робіть це обережно і лише після консультації з цільовим валідатором. + +Ваш валідатор тепер повинен спілкуватися лише з чітко вказаними валідаторами і +лише через порти _Gossip_, _Repair_ та _ServeR_. + +## Налаштування Депозитних Акаунтів + +Акаунти Solana не потребують жодної ініціалізації в мережі; як тільки вони +містять деяку кількість SOL, вони існують. Щоб налаштувати депозитний акаунт для +вашої біржі, просто створіть ключову пару Solana за допомогою будь-якого з наших +[інструментів для гаманців](https://docs.anza.xyz/cli/wallets). + +Рекомендуємо використовувати унікальний депозитний акаунт для кожного з ваших +користувачів. + +Акаунти Solana мають бути звільнені від оренди, містячи еквівалент 2-річної +[оренди](/docs/uk/core/fees.md#rent) у SOL. Щоб визначити мінімальний баланс для +звільнення від оренди для ваших депозитних акаунтів, виконайте запит до +[ендпоінту `getMinimumBalanceForRentExemption`](/docs/uk/rpc/http/getMinimumBalanceForRentExemption.mdx): + +```shell +curl https://api.devnet.solana.com -X POST -H "Content-Type: application/json" -d '{ + "jsonrpc": "2.0", + "id": 1, + "method": "getMinimumBalanceForRentExemption", + "params": [0] +}' +``` + +##### Result + +```json +{ "jsonrpc": "2.0", "result": 890880, "id": 1 } +``` + +### Офлайн Акаунти + +Ви можете залишити ключі для одного або декількох акаунтів колекції офлайн для +підвищення безпеки. У цьому випадку вам потрібно буде переміщати SOL до +"гарячих" акаунтів за допомогою наших +[офлайн-методів](https://docs.anza.xyz/cli/examples/offline-signing). + +## Відстеження Депозитів + +Коли користувач хоче внести SOL на вашу біржу, інструктуйте його виконати +переказ на відповідну депозитну адресу. + +### Міграція Транзакцій із Версіями + +Коли мережа Mainnet Beta почне обробляти транзакції із версіями, біржі +**ЗОБОВ'ЯЗАНІ** внести зміни. Якщо не внести змін, виявлення депозитів +працюватиме неправильно, оскільки отримання транзакції з версією або блоку, що +містить такі транзакції, призведе до помилки. + +- `{"maxSupportedTransactionVersion": 0}` + + Параметр `maxSupportedTransactionVersion` потрібно додати до запитів + `getBlock` і `getTransaction`, щоб уникнути порушення роботи виявлення + депозитів. Остання версія транзакції — `0`, і саме її слід зазначати як + максимальну підтримувану версію транзакції. + +Важливо розуміти, що транзакції з версіями дозволяють користувачам створювати +транзакції, які використовують інший набір ключів акаунтів, завантажених з +ончейн таблиць пошуку адрес. + +- `{"encoding": "jsonParsed"}` + + При отриманні блоків і транзакцій тепер рекомендується використовувати + кодування `"jsonParsed"`, оскільки воно включає всі ключі акаунтів транзакції + (включаючи ті, що з таблиць пошуку) у список `"accountKeys"` повідомлення. Це + спрощує розв'язання змін балансу, описаних у `preBalances` / `postBalances` і + `preTokenBalances` / `postTokenBalances`. + + Якщо використовується кодування `"json"`, записи у `preBalances` / + `postBalances` і `preTokenBalances` / `postTokenBalances` можуть посилатися на + ключі акаунтів, які **НЕ** входять до списку `"accountKeys"` і потребують + розв'язання за допомогою записів `"loadedAddresses"` у метаданих транзакції. + +### Опитування Блоків + +Для відстеження всіх депозитних акаунтів вашої біржі регулярно опитуйте кожен +підтверджений блок і перевіряйте адреси, що вас цікавлять, використовуючи +JSON-RPC сервіс вашої ноди API Solana. + +- Щоб визначити, які блоки доступні, надішліть запит + [`getBlocks`](/docs/uk/rpc/http/getBlocks.mdx), передавши останній блок, який + ви вже обробили, як параметр start-slot: + +```shell +curl https://api.devnet.solana.com -X POST -H "Content-Type: application/json" -d '{ + "jsonrpc": "2.0", + "id": 1, + "method": "getBlocks", + "params": [160017005, 160017015] +}' +``` + +##### Result + +```json +{ + "jsonrpc": "2.0", + "result": [ + 160017005, 160017006, 160017007, 160017012, 160017013, 160017014, 160017015 + ], + "id": 1 +} +``` + +Не кожен слот створює блок, тому в послідовності чисел можуть бути прогалини. + +- Для кожного блоку запитуйте його вміст за допомогою запиту + [`getBlock`](/docs/uk/rpc/http/getBlock.mdx): + +### Поради для Отримання Блоків + +- `{"rewards": false}` + +За замовчуванням отримані блоки містять інформацію про комісії валідаторів за +кожен блок і нагороди за стейкінг на межах епох. Якщо ця інформація вам не +потрібна, вимкніть її за допомогою параметра `"rewards"`. + +- `{"transactionDetails": "accounts"}` + +За замовчуванням отримані блоки містять багато інформації про транзакції та +метадані, які не потрібні для відстеження балансів акаунтів. Встановіть параметр +`"transactionDetails"` для прискорення отримання блоків. + +```shell +curl https://api.devnet.solana.com -X POST -H 'Content-Type: application/json' -d '{ + "jsonrpc": "2.0", + "id": 1, + "method": "getBlock", + "params": [ + 166974442, + { + "encoding": "jsonParsed", + "maxSupportedTransactionVersion": 0, + "transactionDetails": "accounts", + "rewards": false + } + ] +}' +``` + +##### Result + +```json +{ + "jsonrpc": "2.0", + "result": { + "blockHeight": 157201607, + "blockTime": 1665070281, + "blockhash": "HKhao674uvFc4wMK1Cm3UyuuGbKExdgPFjXQ5xtvsG3o", + "parentSlot": 166974441, + "previousBlockhash": "98CNLU4rsYa2HDUyp7PubU4DhwYJJhSX9v6pvE7SWsAo", + "transactions": [ + ... (omit) + { + "meta": { + "err": null, + "fee": 5000, + "postBalances": [ + 1110663066, + 1, + 1040000000 + ], + "postTokenBalances": [], + "preBalances": [ + 1120668066, + 1, + 1030000000 + ], + "preTokenBalances": [], + "status": { + "Ok": null + } + }, + "transaction": { + "accountKeys": [ + { + "pubkey": "9aE476sH92Vz7DMPyq5WLPkrKWivxeuTKEFKd2sZZcde", + "signer": true, + "source": "transaction", + "writable": true + }, + { + "pubkey": "11111111111111111111111111111111", + "signer": false, + "source": "transaction", + "writable": false + }, + { + "pubkey": "G1wZ113tiUHdSpQEBcid8n1x8BAvcWZoZgxPKxgE5B7o", + "signer": false, + "source": "lookupTable", + "writable": true + } + ], + "signatures": [ + "2CxNRsyRT7y88GBwvAB3hRg8wijMSZh3VNYXAdUesGSyvbRJbRR2q9G1KSEpQENmXHmmMLHiXumw4dp8CvzQMjrM" + ] + }, + "version": 0 + }, + ... (omit) + ] + }, + "id": 1 +} +``` + +Поля `preBalances` і `postBalances` дозволяють відстежувати зміни балансу +кожного акаунта без необхідності аналізувати всю транзакцію. Вони містять +початкові та кінцеві баланси кожного акаунта у +[лампортах](/docs/uk/terminology.md#lamport), проіндексовані до списку +`accountKeys`. Наприклад, якщо депозитна адреса, яка вас цікавить, — це +`G1wZ113tiUHdSpQEBcid8n1x8BAvcWZoZgxPKxgE5B7o`, то ця транзакція представляє +переказ 1040000000 - 1030000000 = 10,000,000 лампортів = 0.01 SOL. + +Якщо вам потрібна додаткова інформація про тип транзакції або інші специфічні +дані, ви можете запросити блок із RPC у бінарному форматі та проаналізувати його +за допомогою нашого [Rust SDK](https://github.com/solana-labs/solana) або +[JavaScript SDK](https://github.com/solana-labs/solana-web3.js). + +### Історія Адрес + +Ви також можете запитати історію транзакцій для певної адреси. Це, як правило, +_не_ є життєздатним методом для відстеження всіх ваших депозитних адрес за всіма +слотами, але може бути корисним для аналізу кількох акаунтів за певний період +часу. + +- Надішліть запит + [`getSignaturesForAddress`](/docs/uk/rpc/http/getSignaturesForAddress.mdx) до + API-ноди: + +```shell +curl https://api.devnet.solana.com -X POST -H "Content-Type: application/json" -d '{ + "jsonrpc": "2.0", + "id": 1, + "method": "getSignaturesForAddress", + "params": [ + "3M2b3tLji7rvscqrLAHMukYxDK2nB96Q9hwfV6QkdzBN", + { + "limit": 3 + } + ] +}' +``` + +##### Result + +```json +{ + "jsonrpc": "2.0", + "result": [ + { + "blockTime": 1662064640, + "confirmationStatus": "finalized", + "err": null, + "memo": null, + "signature": "3EDRvnD5TbbMS2mCusop6oyHLD8CgnjncaYQd5RXpgnjYUXRCYwiNPmXb6ZG5KdTK4zAaygEhfdLoP7TDzwKBVQp", + "slot": 148697216 + }, + { + "blockTime": 1662064434, + "confirmationStatus": "finalized", + "err": null, + "memo": null, + "signature": "4rPQ5wthgSP1kLdLqcRgQnkYkPAZqjv5vm59LijrQDSKuL2HLmZHoHjdSLDXXWFwWdaKXUuryRBGwEvSxn3TQckY", + "slot": 148696843 + }, + { + "blockTime": 1662064341, + "confirmationStatus": "finalized", + "err": null, + "memo": null, + "signature": "36Q383JMiqiobuPV9qBqy41xjMsVnQBm9rdZSdpbrLTGhSQDTGZJnocM4TQTVfUGfV2vEX9ZB3sex6wUBUWzjEvs", + "slot": 148696677 + } + ], + "id": 1 +} +``` + +- Для кожного отриманого підпису отримайте деталі транзакції, надіславши запит + [`getTransaction`](/docs/uk/rpc/http/getTransaction.mdx): + +```shell +curl https://api.devnet.solana.com -X POST -H 'Content-Type: application/json' -d '{ + "jsonrpc":"2.0", + "id":1, + "method":"getTransaction", + "params":[ + "2CxNRsyRT7y88GBwvAB3hRg8wijMSZh3VNYXAdUesGSyvbRJbRR2q9G1KSEpQENmXHmmMLHiXumw4dp8CvzQMjrM", + { + "encoding":"jsonParsed", + "maxSupportedTransactionVersion":0 + } + ] +}' +``` + +##### Result + +```json +{ + "jsonrpc": "2.0", + "result": { + "blockTime": 1665070281, + "meta": { + "err": null, + "fee": 5000, + "innerInstructions": [], + "logMessages": [ + "Program 11111111111111111111111111111111 invoke [1]", + "Program 11111111111111111111111111111111 success" + ], + "postBalances": [1110663066, 1, 1040000000], + "postTokenBalances": [], + "preBalances": [1120668066, 1, 1030000000], + "preTokenBalances": [], + "rewards": [], + "status": { + "Ok": null + } + }, + "slot": 166974442, + "transaction": { + "message": { + "accountKeys": [ + { + "pubkey": "9aE476sH92Vz7DMPyq5WLPkrKWivxeuTKEFKd2sZZcde", + "signer": true, + "source": "transaction", + "writable": true + }, + { + "pubkey": "11111111111111111111111111111111", + "signer": false, + "source": "transaction", + "writable": false + }, + { + "pubkey": "G1wZ113tiUHdSpQEBcid8n1x8BAvcWZoZgxPKxgE5B7o", + "signer": false, + "source": "lookupTable", + "writable": true + } + ], + "addressTableLookups": [ + { + "accountKey": "4syr5pBaboZy4cZyF6sys82uGD7jEvoAP2ZMaoich4fZ", + "readonlyIndexes": [], + "writableIndexes": [3] + } + ], + "instructions": [ + { + "parsed": { + "info": { + "destination": "G1wZ113tiUHdSpQEBcid8n1x8BAvcWZoZgxPKxgE5B7o", + "lamports": 10000000, + "source": "9aE476sH92Vz7DMPyq5WLPkrKWivxeuTKEFKd2sZZcde" + }, + "type": "transfer" + }, + "program": "system", + "programId": "11111111111111111111111111111111" + } + ], + "recentBlockhash": "BhhivDNgoy4L5tLtHb1s3TP19uUXqKiy4FfUR34d93eT" + }, + "signatures": [ + "2CxNRsyRT7y88GBwvAB3hRg8wijMSZh3VNYXAdUesGSyvbRJbRR2q9G1KSEpQENmXHmmMLHiXumw4dp8CvzQMjrM" + ] + }, + "version": 0 + }, + "id": 1 +} +``` + +## Відправлення Виведення + +Щоб виконати запит користувача на виведення SOL, ви повинні створити транзакцію +переказу Solana та надіслати її на API-ноду для передачі в кластер. + +### Синхронний Переказ + +Відправлення синхронного переказу до кластера Solana дозволяє легко +переконатися, що переказ успішно завершено та підтверджено кластером. + +Інструмент командного рядка Solana пропонує просту команду `solana transfer` для +створення, подання та підтвердження транзакцій переказу. За замовчуванням цей +метод чекатиме та відстежуватиме прогрес через stderr, доки транзакція не буде +підтверджена кластером. У разі невдачі транзакції буде повідомлено про будь-які +помилки. + +```shell +solana transfer --allow-unfunded-recipient --keypair --url http://localhost:8899 +``` + +[Solana Javascript SDK](https://github.com/solana-labs/solana-web3.js) пропонує +схожий підхід для екосистеми JS. Використовуйте `SystemProgram` для створення +транзакції переказу та надсилайте її за допомогою методу +`sendAndConfirmTransaction`. + +### Асинхронний Переказ + +Для більшої гнучкості ви можете надсилати перекази на виведення асинхронно. У +цьому випадку саме ви несете відповідальність за перевірку успішності транзакції +та її підтвердження кластером. + +**Примітка:** Кожна транзакція містить +[recent blockhash](/docs/uk/core/transactions.md#recent-blockhash), що вказує на +її актуальність. Важливо **дочекатися**, поки цей blockhash не стане недійсним, +перш ніж повторювати спробу переказу, який, схоже, не було підтверджено або +завершено кластером. Інакше ви ризикуєте створити подвійний витрату. Дивіться +більше про [термін дії blockhash](#blockhash-expiration) нижче. + +Спочатку отримайте недавній blockhash за допомогою ендпоінту +[`getFees`](/docs/uk/rpc/deprecated/getFees.mdx) або команди CLI: + +```shell +solana fees --url http://localhost:8899 +``` + +У командному рядку передайте аргумент `--no-wait`, щоб відправити переказ +асинхронно, і додайте ваш недавній blockhash за допомогою аргументу +`--blockhash`: + +```shell +solana transfer --no-wait --allow-unfunded-recipient --blockhash --keypair --url http://localhost:8899 +``` + +Ви також можете створити, підписати та серіалізувати транзакцію вручну, а потім +надіслати її до кластера за допомогою ендпоінта JSON-RPC +[`sendTransaction`](/docs/uk/rpc/http/sendTransaction.mdx). + +#### Підтвердження Транзакцій та Фінальність + +Отримайте статус групи транзакцій за допомогою ендпоінта JSON-RPC +[`getSignatureStatuses`](/docs/uk/rpc/http/getSignatureStatuses.mdx). Поле +`confirmations` вказує, скільки +[підтверджених блоків](/docs/uk/terminology.md#confirmed-block) минуло з моменту +обробки транзакції. Якщо `confirmations: null`, це означає, що транзакція є +[фіналізованою](/docs/uk/terminology.md#finality). + +```shell +curl https://api.devnet.solana.com -X POST -H "Content-Type: application/json" -d '{ + "jsonrpc":"2.0", + "id":1, + "method":"getSignatureStatuses", + "params":[ + [ + "5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW", + "5j7s6NiJS3JAkvgkoc18WVAsiSaci2pxB2A6ueCJP4tprA2TFg9wSyTLeYouxPBJEMzJinENTkpA52YStRW5Dia7" + ] + ] +}' +``` + +##### Result + +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 82 + }, + "value": [ + { + "slot": 72, + "confirmations": 10, + "err": null, + "status": { + "Ok": null + } + }, + { + "slot": 48, + "confirmations": null, + "err": null, + "status": { + "Ok": null + } + } + ] + }, + "id": 1 +} +``` + +#### Термін Дії Blockhash + +Ви можете перевірити, чи є конкретний blockhash ще дійсним, надіславши запит +[`getFeeCalculatorForBlockhash`](/docs/uk/rpc/deprecated/getFeeCalculatorForBlockhash.mdx) +з blockhash як параметром. Якщо значення у відповіді `null`, blockhash +недійсний, і транзакція на виведення, яка використовує цей blockhash, не має +шансів на успіх. + +### Перевірка Адрес Акаунтів, Наданих Користувачами, для Виведення + +Оскільки транзакції на виведення є незворотними, хорошою практикою може бути +перевірка адреси акаунта, наданої користувачем, перед авторизацією виведення, +щоб запобігти випадковій втраті коштів користувача. + +#### Основна Перевірка + +Адреси Solana — це 32-байтовий масив, закодований за допомогою алфавіту base58 +від Bitcoin. Це призводить до отримання ASCII-рядка, що відповідає наступному +регулярному виразу: + +```text +[1-9A-HJ-NP-Za-km-z]{32,44} +``` + +Ця перевірка сама по собі є недостатньою, оскільки адреси Solana не мають +контрольної суми, тому помилки друку не можуть бути виявлені. Для додаткової +перевірки введення користувачем можна декодувати рядок і підтвердити, що довжина +отриманого байтового масиву дорівнює 32. Однак існують адреси, які можуть +декодуватися у 32 байти, незважаючи на помилки, наприклад, пропущений символ, +перестановка символів або ігнорування регістру. + +#### Розширена Перевірка + +Через вразливість до помилок друку, описану вище, рекомендується запитувати +баланс для можливих адрес виведення та запитувати у користувача підтвердження, +якщо буде виявлено ненульовий баланс. + +#### Перевірка Валідного ed25519 Публічного Ключа + +Адреса звичайного акаунта в Solana — це Base58-кодований рядок 256-бітного +публічного ключа ed25519. Не всі бітові патерни є валідними публічними ключами +для кривої ed25519, тому можна забезпечити, що адреси акаунтів, надані +користувачем, принаймні є правильними публічними ключами ed25519. + +#### Java + +Ось приклад на Java для перевірки адреси, наданої користувачем, як валідного +публічного ключа ed25519: + +Наступний приклад коду передбачає використання Maven. + +`pom.xml`: + +```xml + + ... + + spring + https://repo.spring.io/libs-release/ + + + +... + + + ... + + io.github.novacrypto + Base58 + 0.1.3 + + + cafe.cryptography + curve25519-elisabeth + 0.1.0 + + +``` + +```java +import io.github.novacrypto.base58.Base58; +import cafe.cryptography.curve25519.CompressedEdwardsY; + +public class PubkeyValidator +{ + public static boolean verifyPubkey(String userProvidedPubkey) + { + try { + return _verifyPubkeyInternal(userProvidedPubkey); + } catch (Exception e) { + return false; + } + } + + public static boolean _verifyPubkeyInternal(String maybePubkey) throws Exception + { + byte[] bytes = Base58.base58Decode(maybePubkey); + return !(new CompressedEdwardsY(bytes)).decompress().isSmallOrder(); + } +} +``` + +## Мінімальні Суми Депозиту та Виведення + +Кожен депозит та виведення SOL повинні бути більшими або дорівнювати +мінімальному балансу, звільненому від оренди, для акаунта за адресою гаманця +(базовий акаунт SOL, який не містить даних), який наразі складає: **0.000890880 +SOL**. + +Аналогічно, кожен депозитний акаунт повинен містити принаймні цей баланс. + +```shell +curl https://api.devnet.solana.com -X POST -H "Content-Type: application/json" -d '{ + "jsonrpc": "2.0", + "id": 1, + "method": "getMinimumBalanceForRentExemption", + "params": [0] +}' +``` + +##### Result + +```json +{ "jsonrpc": "2.0", "result": 890880, "id": 1 } +``` + +## Пріоритетні Комісії та Обчислювальні Одиниці + +У періоди високого попиту транзакція може стати недійсною до того, як валідатор +включить її до блоку, оскільки були обрані інші транзакції з вищою економічною +цінністю. Валідні транзакції в Solana можуть бути затримані або скасовані, якщо +Пріоритетні Комісії не впроваджені належним чином. + +[Пріоритетні Комісії](/docs/uk/terminology.md#prioritization-fee) — це додаткові +комісії, які можна додати до +[базової комісії за транзакцію](/docs/uk/core/fees.md#transaction-fees), щоб +забезпечити включення транзакцій у блоки і їх доставку. + +Ці пріоритетні комісії додаються до транзакції шляхом додавання спеціальної +інструкції `Compute Budget`, яка встановлює бажану суму комісії. + + + +Якщо ці інструкції не впровадити, це може призвести до збоїв у роботі мережі та +скасування транзакцій. Наполегливо рекомендується кожній біржі, що підтримує +Solana, використовувати пріоритетні комісії для уникнення збоїв. + + + +### Що таке Пріоритетна Комісія? + +Пріоритетні комісії виражаються у мікролампортах за обчислювальну одиницю +(наприклад, невеликі суми SOL) і додаються до транзакцій, щоб зробити їх +економічно привабливими для валідаторів і забезпечити їх включення до блоків у +мережі. + +### Якою має бути Пріоритетна Комісія? + +Метод встановлення пріоритетної комісії має включати запити до недавніх значень +пріоритетних комісій, щоб встановити розмір комісії, яка буде привабливою для +мережі. Використовуючи метод RPC +[`getRecentPrioritizationFees`](/docs/uk/rpc/http/getrecentprioritizationfees), +можна отримати дані про пріоритетні комісії, необхідні для підтвердження +транзакції в недавньому блоці. + +Стратегія ціноутворення пріоритетних комісій залежить від ваших потреб. +Універсального підходу не існує. Однією зі стратегій може бути розрахунок рівня +успішності ваших транзакцій і коригування пріоритетної комісії відповідно до +даних з API про комісії. Ціноутворення на пріоритетні комісії є динамічним і +залежить від активності в мережі та ставок інших учасників. + +### Як Впровадити Пріоритетні Комісії + +Додавання пріоритетних комісій до транзакції включає додавання двох інструкцій +Compute Budget: + +- для встановлення ціни за обчислювальну одиницю +- для встановлення ліміту обчислювальних одиниць + +> Детальний +> [посібник для розробників про використання пріоритетних комісій](/content/guides/advanced/how-to-use-priority-fees.md) +> доступний для додаткової інформації. + +Створіть інструкцію `setComputeUnitPrice`, щоб додати Пріоритетну Комісію понад +Базову Комісію за Транзакцію (5,000 лампортів). + +```typescript +// import { ComputeBudgetProgram } from "@solana/web3.js" +ComputeBudgetProgram.setComputeUnitPrice({ microLamports: number }); +``` + +Значення, надане в мікролампортах, буде множитися на обчислювальний бюджет +(Compute Unit, CU), щоб визначити Пріоритетну Комісію в лампортах. Наприклад, +якщо ваш бюджет CU становить 1M CU, і ви додаєте `1 мікролампорта/CU`, +Пріоритетна Комісія становитиме 1 лампорт (1M \* 0.000001). Загальна комісія +складе 5001 лампорт. + +Щоб встановити новий обчислювальний бюджет для транзакції, створіть інструкцію +`setComputeUnitLimit`. + +```typescript +// import { ComputeBudgetProgram } from "@solana/web3.js" +ComputeBudgetProgram.setComputeUnitLimit({ units: number }); +``` + +Значення `units`, яке ви надаєте, замінить стандартне значення обчислювального +бюджету (Compute Budget) в середовищі виконання Solana. + + + +Транзакції повинні запитувати мінімальну кількість обчислювальних одиниць (CU), +необхідну для виконання, щоб максимізувати пропускну здатність і мінімізувати +загальні комісії. + +Ви можете дізнатися, скільки CU споживає транзакція, надіславши її в інший +кластер Solana, наприклад, devnet. Наприклад, +[простий переказ токенів](https://explorer.solana.com/tx/5scDyuiiEbLxjLUww3APE9X7i8LE3H63unzonUwMG7s2htpoAGG17sgRsNAhR1zVs6NQAnZeRVemVbkAct5myi17) +займає 300 CU. + + + +```typescript +// import { ... } from "@solana/web3.js" + +const modifyComputeUnits = ComputeBudgetProgram.setComputeUnitLimit({ + // note: set this to be the lowest actual CU consumed by the transaction + units: 300, +}); + +const addPriorityFee = ComputeBudgetProgram.setComputeUnitPrice({ + microLamports: 1, +}); + +const transaction = new Transaction() + .add(modifyComputeUnits) + .add(addPriorityFee) + .add( + SystemProgram.transfer({ + fromPubkey: payer.publicKey, + toPubkey: toAccount, + lamports: 10000000, + }), + ); +``` + +### Пріоритетні Комісії та Транзакції з Durable Nonces + +Якщо у вашій системі використовуються транзакції з Durable Nonces, важливо +правильно впровадити Пріоритетні Комісії разом із Durable Transaction Nonces, +щоб забезпечити успішне виконання транзакцій. Якщо цього не зробити, заплановані +Durable Nonce транзакції не будуть розпізнані належним чином. + +Якщо ви ВИКОРИСТОВУЄТЕ Durable Transaction Nonces, інструкція +`AdvanceNonceAccount` МАЄ бути зазначена ПЕРШОЮ у списку інструкцій, навіть якщо +використовуються інструкції обчислювального бюджету для встановлення +пріоритетних комісій. + +Специфічний приклад коду, що демонструє використання durable nonces і +пріоритетних комісій разом, можна знайти у +[керівництві для розробників](/content/guides/advanced/how-to-use-priority-fees.md#special-considerations). + +## Підтримка Стандарту SPL Token + +[SPL Token](https://spl.solana.com/token) є стандартом для створення і обміну +обгорнутих/синтетичних токенів у блокчейні Solana. + +Робочий процес SPL Token схожий на той, що використовується для нативних SOL +токенів, але є кілька відмінностей, які будуть розглянуті в цьому розділі. + +### Токен Mints + +Кожен _тип_ SPL Token декларується шляхом створення акаунта _mint_. Цей акаунт +зберігає метадані, які описують характеристики токена, такі як пропозиція, +кількість десяткових знаків і різні повноваження з контролю за mint. Кожен +акаунт SPL Token посилається на відповідний mint і може взаємодіяти лише з SPL +Token цього типу. + +### Встановлення CLI Інструменту `spl-token` + +Акаунти SPL Token можна запитувати та змінювати за допомогою утиліти командного +рядка `spl-token`. Приклади, наведені в цьому розділі, залежать від того, що +вона встановлена на вашій локальній системі. + +`spl-token` розповсюджується з Rust +[crates.io](https://crates.io/crates/spl-token) через утиліту командного рядка +Rust `cargo`. Останню версію `cargo` можна встановити за допомогою простого +скрипта для вашої платформи на [rustup.rs](https://rustup.rs). Після +встановлення `cargo`, утиліту `spl-token` можна отримати за допомогою такої +команди: + +```shell +cargo install spl-token-cli +``` + +Після цього ви можете перевірити встановлену версію, щоб переконатися у +правильності встановлення: + +```shell +spl-token --version +``` + +Результат має виглядати приблизно так: + +```text +spl-token-cli 2.0.1 +``` + +### Створення Акаунтів + +Акаунти SPL Token мають додаткові вимоги, яких не мають нативні акаунти System +Program: + +1. Акаунти SPL Token мають бути створені до того, як у них можна буде внести + токени. Акаунти токенів можна створити явно за допомогою команди + `spl-token create-account` або неявно за допомогою команди + `spl-token transfer --fund-recipient ...`. +2. Акаунти SPL Token повинні залишатися + [звільненими від оренди](/docs/uk/core/fees.md#rent-exempt) протягом усього + періоду їх існування, а отже, вимагають внесення невеликої кількості нативних + SOL токенів під час створення акаунта. Для акаунтів SPL Token ця сума + становить 0.00203928 SOL (2,039,280 лампортів). + +#### Командний Рядок + +Щоб створити акаунт SPL Token з такими властивостями: + +1. Асоційований із зазначеним mint +2. Належить ключовій парі фінансуючого акаунта + +```shell +spl-token create-account +``` + +#### Приклад + +```shell +spl-token create-account AkUFCWTXb3w9nY2n6SFJvBV6VwvFUCe4KBMCcgLsa2ir +``` + +Результат: + +``` +Creating account 6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkV +Signature: 4JsqZEPra2eDTHtHpB4FMWSfk3UgcCVmkKkP7zESZeMrKmFFkDkNd91pKP3vPVVZZPiu5XxyJwS73Vi5WsZL88D7 +``` + +Або щоб створити акаунт SPL Token з конкретною ключовою парою: + +```shell +solana-keygen new -o token-account.json + +spl-token create-account AkUFCWTXb3w9nY2n6SFJvBV6VwvFUCe4KBMCcgLsa2ir token-account.json +``` + +Результат: + +```shell +Creating account 6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkV +Signature: 4JsqZEPra2eDTHtHpB4FMWSfk3UgcCVmkKkP7zESZeMrKmFFkDkNd91pKP3vPVVZZPiu5XxyJwS73Vi5WsZL88D7 +``` + +### Перевірка Балансу Акаунта + +#### Командний Рядок + +Щоб перевірити баланс акаунта SPL Token, використовуйте наступну команду: + +```shell +spl-token balance +``` + +#### Приклад + +```shell +solana balance 6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkV +``` + +Результат: + +``` +0 +``` + +### Переказ Токенів + +Вихідним акаунтом для переказу є фактичний акаунт токенів, який містить +необхідну суму. + +Однак адресою отримувача може бути звичайний гаманець. Якщо асоційований токен +акаунт для вказаного mint ще не існує для цього гаманця, переказ створить його, +якщо буде вказаний аргумент `--fund-recipient`. + +#### Командний Рядок + +Щоб виконати переказ токенів, використовуйте наступну команду: + +```shell +spl-token transfer --fund-recipient +``` + +#### Приклад + +```shell +spl-token transfer 6B199xxzw3PkAm25hGJpjj3Wj3WNYNHzDAnt1tEqg5BN 1 +``` + +Результат: + +```shell +6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkV +Transfer 1 tokens + Sender: 6B199xxzw3PkAm25hGJpjj3Wj3WNYNHzDAnt1tEqg5BN + Recipient: 6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkV +Signature: 3R6tsog17QM8KfzbcbdP4aoMfwgo6hBggJDVy7dZPVmH2xbCWjEj31JKD53NzMrf25ChFjY7Uv2dfCDq4mGFFyAj +``` + +### Депозити + +Оскільки кожна пара `(гаманець, mint)` потребує окремого акаунта в ончейні, +рекомендується, щоб адреси для цих акаунтів були отримані з гаманців для +депозиту SOL за допомогою схеми +[Associated Token Account (ATA)](https://spl.solana.com/associated-token-account), +і приймалися _лише_ депозити з ATA адрес. + +Відстеження транзакцій депозиту має використовувати метод +[опитування блоків](#poll-for-blocks), описаний вище. Кожен новий блок слід +сканувати на наявність успішних транзакцій, що посилаються на адреси акаунтів, +отриманих для користувачів. Поля `preTokenBalance` і `postTokenBalance` з +метаданих транзакцій необхідно використовувати для визначення ефективної зміни +балансу. Ці поля ідентифікують mint токена та власника акаунта (основну адресу +гаманця) відповідного акаунта. + +Зауважте, що якщо акаунт для отримання створюється під час транзакції, у нього +не буде запису `preTokenBalance`, оскільки стан акаунта раніше не існував. У +цьому випадку початковий баланс можна вважати нульовим. + +### Виведення + +Адреса для виведення, надана користувачем, має бути адресою їх SOL гаманця. + +Перед виконанням [переказу](#token-transfers) для виведення біржа повинна +перевірити адресу, як це +[описано вище](#validating-user-supplied-account-addresses-for-withdrawals). +Крім того, ця адреса має належати System Program і не мати даних акаунта. Якщо +на цій адресі відсутній баланс SOL, перед виконанням виведення слід отримати +підтвердження користувача. Усі інші адреси для виведення повинні бути відхилені. + +З адреси для виведення +[Associated Token Account (ATA)](https://spl.solana.com/associated-token-account) +для відповідного mint отримується, і переказ виконується на цей акаунт за +допомогою інструкції +[TransferChecked](https://github.com/solana-labs/solana-program-library/blob/fc0d6a2db79bd6499f04b9be7ead0c400283845e/token/program/src/instruction.rs#L268). +Зауважте, що ATA адреса може ще не існувати, у цьому випадку біржа повинна +профінансувати акаунт від імені користувача. Для акаунтів SPL Token фінансування +акаунта для виведення потребує 0.00203928 SOL (2,039,280 лампортів). + +Шаблон команди `spl-token transfer` для виведення: + +```shell +spl-token transfer --fund-recipient +``` + +### Інші Міркування + +#### Freeze Authority (Замороження Акаунтів) + +Для дотримання регуляторних вимог емітент токенів SPL може опціонально мати +"Freeze Authority" (повноваження замороження) для всіх акаунтів, створених у +зв'язку з його mint. Це дозволяє йому +[заморожувати](https://spl.solana.com/token#freezing-accounts) активи в певному +акаунті за бажанням, роблячи акаунт недоступним до моменту його розморожування. +Якщо ця функція використовується, публічний ключ freeze authority буде +зареєстрований у акаунті mint токену SPL. + +### Основна Підтримка Стандарту SPL Token-2022 (Token-Extensions) + +[SPL Token-2022](https://spl.solana.com/token-2022) є новим стандартом для +створення й обміну обгорнутих/синтетичних токенів у блокчейні Solana. + +Відомий також як "Token Extensions", цей стандарт включає багато нових функцій, +які можуть бути опціонально увімкнені творцями токенів та власниками акаунтів. +До таких функцій належать конфіденційні перекази, комісії за переказ, закриття +mint, метадані, постійні делегати, незмінна власність тощо. Більше інформації +дивіться в +[керівництві з розширень](https://spl.solana.com/token-2022/extensions). + +Якщо ваша біржа підтримує SPL Token, багато додаткових зусиль для підтримки SPL +Token-2022 не знадобиться: + +- CLI інструмент безпроблемно працює з обома програмами, починаючи з версії + 3.0.0. +- Поля `preTokenBalances` та `postTokenBalances` включають баланси SPL + Token-2022. +- RPC індексує акаунти SPL Token-2022, але їх потрібно запитувати окремо за + програмним ідентифікатором `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`. + +Програма Associated Token Account працює так само, і правильно розраховує +необхідну суму депозиту SOL для нового акаунта. + +Однак через розширення акаунти можуть бути більшими за 165 байтів, тому вони +можуть потребувати більше ніж 0.00203928 SOL для фінансування. + +Наприклад, програма Associated Token Account завжди включає розширення +"immutable owner", тому акаунти займають мінімум 170 байтів, що вимагає +0.00207408 SOL. + +### Міркування Щодо Розширень + +Попередній розділ описує базову підтримку SPL Token-2022. Оскільки розширення +змінюють поведінку токенів, біржам, можливо, доведеться змінити, як вони +обробляють токени. + +Можливо побачити всі розширення на mint або токен акаунті за допомогою наступної +команди: + +```shell +spl-token display +``` + +#### Комісія за Переказ + +Токен може бути налаштований з комісією за переказ, при якій частина переданих +токенів утримується на адресі отримувача для подальшого стягнення. + +Якщо ваша біржа здійснює переказ цих токенів, зверніть увагу, що не всі токени +можуть надійти на адресу отримувача через утриману суму. + +Під час переказу можна вказати очікувану комісію, щоб уникнути несподіванок: + +```shell +spl-token transfer --expected-fee --fund-recipient +``` + +#### Повноваження Закриття Mint + +З цим розширенням творець токена може закрити mint, якщо пропозиція токенів +дорівнює нулю. + +Коли mint закривається, можуть залишатися порожні токен акаунти, які більше не +будуть асоційовані з дійсним mint. + +Ці токен акаунти можна безпечно закрити за допомогою наступної команди: + +```shell +spl-token close --address +``` + +#### Конфіденційні Перекази + +Mint може бути налаштований для конфіденційних переказів, при яких суми токенів +шифруються, але власники акаунтів залишаються публічними. + +Біржі можуть налаштувати токен акаунти для відправлення та отримання +конфіденційних переказів, щоб приховати суми користувачів. Увімкнення +конфіденційних переказів для токен акаунтів не є обов’язковим, тому біржі можуть +змусити користувачів надсилати токени неконфіденційно. + +Щоб увімкнути конфіденційні перекази, акаунт має бути налаштований відповідним +чином: + +```shell +spl-token configure-confidential-transfer-account --address +``` + +Для переказу: + +```shell +spl-token transfer --confidential +``` + +Під час конфіденційного переказу поля `preTokenBalance` та `postTokenBalance` не +показуватимуть змін. Щоб виконати операцію з депозитними акаунтами, необхідно +розшифрувати новий баланс, щоб вивести токени: + +```shell +spl-token apply-pending-balance --address +spl-token withdraw-confidential-tokens --address +``` + +#### Стандартний Стан Акаунтів + +Mint може бути налаштований із стандартним станом акаунтів, коли всі нові токен +акаунти за замовчуванням заморожені. Творці токенів можуть вимагати від +користувачів проходження окремого процесу для розморожування акаунта. + +#### Непередавані Токени + +Деякі токени є непередаваними, але їх все ще можна спалити, а акаунт закрити. + +#### Постійний Делегат + +Творці токенів можуть призначити постійного делегата для всіх своїх токенів. +Постійний делегат може передавати або спалювати токени з будь-якого акаунта, +потенційно викрадаючи кошти. + +Це може бути юридичною вимогою для стейблкоїнів у певних юрисдикціях або +використовуватися для схем повернення токенів. + +Будьте уважні, оскільки ці токени можуть бути передані без відома вашої біржі. + +#### Перехоплювач Переказів (Transfer Hook) + +Токени можуть бути налаштовані з додатковою програмою, яку необхідно викликати +під час переказів для перевірки транзакції або виконання іншої логіки. + +Оскільки середовище виконання Solana вимагає, щоб усі акаунти були явно передані +до програми, а перехоплювачі переказів вимагають додаткових акаунтів, біржа +повинна створювати інструкції для переказу цих токенів по-іншому. + +CLI та творці інструкцій, такі як +`createTransferCheckedWithTransferHookInstruction`, додають додаткові акаунти +автоматично, але також можна вказати додаткові акаунти явно: + +```shell +spl-token transfer --transfer-hook-account --transfer-hook-account ... +``` + +#### Обов'язкова Нотатка (Memo) при Переказі + +Користувачі можуть налаштувати свої токен акаунти так, щоб перекази вимагали +нотатку (memo). + +Біржі можуть додавати інструкцію нотатки перед тим, як переказати токени +користувачам, або вимагати, щоб користувачі додавали нотатку перед відправкою +токенів на біржу: + +```shell +spl-token transfer --with-memo +``` + +## Тестування Інтеграції + +Обов'язково протестуйте весь свій робочий процес у кластерах Solana devnet та +testnet [clusters](/docs/uk/core/clusters.md) перед переходом до продакшну на +mainnet-beta. Devnet є найбільш відкритим і гнучким, і ідеально підходить для +початкової розробки, тоді як testnet пропонує більш реалістичну конфігурацію +кластера. Обидва кластери devnet та testnet підтримують faucet. Використовуйте +команду `solana airdrop 1`, щоб отримати трохи SOL для devnet або testnet для +розробки та тестування. diff --git a/docs/locales/uk/more/index.md b/docs/locales/uk/more/index.md new file mode 100644 index 000000000..6243eccd2 --- /dev/null +++ b/docs/locales/uk/more/index.md @@ -0,0 +1,6 @@ +--- +metaOnly: true +title: Більше інформації +# note: sort order is set to a really high number so this section is at the bottom of the sidebar +sidebarSortOrder: 9999 +--- diff --git a/docs/locales/uk/programs/anchor/client-typescript.md b/docs/locales/uk/programs/anchor/client-typescript.md new file mode 100644 index 000000000..a2ff868f0 --- /dev/null +++ b/docs/locales/uk/programs/anchor/client-typescript.md @@ -0,0 +1,354 @@ +--- +title: JS/TS Client +description: + Дізнайтеся, як використовувати клієнтську бібліотеку TypeScript для взаємодії + з Solana +sidebarLabel: JS/TS Client +sidebarSortOrder: 3 +--- + +Anchor надає бібліотеку клієнта TypeScript +([@coral-xyz/anchor](https://github.com/coral-xyz/anchor/tree/v0.30.1/ts/packages/anchor)) +Це спрощує процес взаємодії з програмами Solana від клієнта у JavaScript або +TypeScript. + +## Клієнтська програма + +Для використання клієнтської бібліотеки спочатку створіть екземпляр +[`Program`](https://github.com/coral-xyz/anchor/blob/v0.30.1/ts/packages/anchor/src/program/index.ts#L58) +Використання [IDL -файлу] (/DOCS/Програми/Анкер/IDL), створений Anchor. + +Створення екземпляра програми вимагає IDL програми та +[`AnchorProvider`](https://github.com/coral-xyz/anchor/blob/v0.30.1/ts/packages/anchor/src/provider.ts#L55). +`AnchorProvider` - це абстракція, яка поєднує дві речі: + +- `Підключення ' - з'єднання з [кластером Solana] (/docs/core/clusters.md) (тобто + localhost, devnet, mainnet) +- `Wallet` - (необов’язково) Гаманець за замовчуванням, який використовується + для оплати та підписання транзакцій + + + +При інтеграції з фронтендом за допомогою [Адаптер гаманця] (https://solana.com/developers/guides/wallets/add-solana-wallet-adapter-to-nextjs), +Вам потрібно буде налаштувати `AnchorProvider` та `Program`. + +```ts {9-10, 12-14} +import { Program, AnchorProvider, setProvider } from "@coral-xyz/anchor"; +import { useAnchorWallet, useConnection } from "@solana/wallet-adapter-react"; +import type { HelloAnchor } from "./idlType"; +import idl from "./idl.json"; + +const { connection } = useConnection(); +const wallet = useAnchorWallet(); + +const provider = new AnchorProvider(connection, wallet, {}); +setProvider(provider); + +export const program = new Program(idl as HelloAnchor, { + connection, +}); +``` + +У фрагменті коду вище: + +- `idl.json` - це файл IDL, створений якір, знайдено на + `/target/idl/ .json` в якорі. +- `idltype.ts` - це тип IDL (для використання з TS), знайдено в + `/target/type/ .ts` в якорі. + +Крім того, ви можете створити екземпляр, використовуючи лише IDL і підключення +до кластеру солани.Це означає, що немає за замовчуванням `Wallet`, але дозволяє +використовувати` Програму 'для отримання облікових записів або побудувати +Інструкції без підключеного гаманця. + +```ts {8-10} +import { clusterApiUrl, Connection, PublicKey } from "@solana/web3.js"; +import { Program } from "@coral-xyz/anchor"; +import type { HelloAnchor } from "./idlType"; +import idl from "./idl.json"; + +const connection = new Connection(clusterApiUrl("devnet"), "confirmed"); + +export const program = new Program(idl as HelloAnchor, { + connection, +}); +``` + + + + +Якір автоматично налаштовує екземпляр `Program` у тестовому файлі за +замовчуванням нові проекти.Однак ця установка відрізняється від того, як ви +ініціалізуєте програму Поза робочою областю якоря, наприклад, у програмах React +або Node.js. + +```typescript +import * as anchor from "@coral-xyz/anchor"; +import { Program } from "@coral-xyz/anchor"; +import { HelloAnchor } from "../target/types/hello_anchor"; + +describe("hello_anchor", () => { + // Configure the client to use the local cluster. + anchor.setProvider(anchor.AnchorProvider.env()); + + const program = anchor.workspace.HelloAnchor as Program; + + it("Is initialized!", async () => { + // Add your test here. + const tx = await program.methods.initialize().rpc(); + console.log("Your transaction signature", tx); + }); +}); +``` + + + + +## Виклик інструкцій + +Після того як `Program` налаштовано за допомогою програмного IDL, ви можете +використовувати якір +[`MethodsBuilder`](https://github.com/coral-xyz/anchor/blob/v0.30.1/ts/packages/anchor/src/program/namespace/methods.ts#L155) +для: + +- Створіть окремі інструкції +- Будуйте транзакції +- Будуйте та надсилайте транзакції + +Основний формат виглядає як наступне: + + + + + +`program.methods` - Це API Builder для створення інструкційних дзвінків з IDL +програми + +```ts /methods/ {1} +await program.methods + .instructionName(instructionData) + .accounts({}) + .signers([]) + .rpc(); +``` + + + + +У розділі `.methods` вказуйте назву інструкції з IDL програми, передаючи +будь-які необхідні аргументи як значення, розділені комами. + +```ts /instructionName/ /instructionData1/ /instructionData2/ {2} +await program.methods + .instructionName(instructionData1, instructionData2) + .accounts({}) + .signers([]) + .rpc(); +``` + + + + +`.accounts` - Вказуйте адресу облікових записів, необхідних для інструкції, як +це зазначено в IDL. + +```ts /accounts/ {3} +await program.methods + .instructionName(instructionData) + .accounts({}) + .signers([]) + .rpc(); +``` + +Зверніть увагу, що деякі адреси облікових записів не потрібно вказувати явно, +оскільки клієнт Anchor може автоматично їх визначити. Це зазвичай стосується: + +- Загальних облікових записів (наприклад, Програма Системи) +- Облікових записів, де адреса є PDA (Програма-Походження Адреси) + + + + +`.signers` - Необов'язково передайте масив ключових пар, які потрібні як +додаткові підписанти для інструкції. Це зазвичай використовується при створенні +нових облікових записів, де адреса облікового запису є публічним ключем +нещодавно згенерованої ключової пари. + +```ts /signers/ {4} +await program.methods + .instructionName(instructionData) + .accounts({}) + .signers([]) + .rpc(); +``` + +Зверніть увагу, що `.signers` слід використовувати тільки при використанні +`.rpc()`. Коли ви використовуєте `.transaction()` або `.instruction()`, +підписанти повинні бути додані до транзакції перед її відправкою. + + + + +Anchor надає кілька методів для створення інструкцій програми: + + + + + +Метод +[`rpc()`](https://github.com/coral-xyz/anchor/blob/v0.30.1/ts/packages/anchor/src/program/namespace/methods.ts#L283) +[відправляє підписану транзакцію](https://github.com/coral-xyz/anchor/blob/v0.30.1/ts/packages/anchor/src/program/namespace/rpc.ts#L29) +з вказаною інструкцією та повертає `TransactionSignature`. + +При використанні `.rpc` гаманець з `Provider` автоматично додається як +підписант. + +```ts {13} +// Generate keypair for the new account +const newAccountKp = new Keypair(); + +const data = new BN(42); +const transactionSignature = await program.methods + .initialize(data) + .accounts({ + newAccount: newAccountKp.publicKey, + signer: wallet.publicKey, + systemProgram: SystemProgram.programId, + }) + .signers([newAccountKp]) + .rpc(); +``` + + + + +Метод +[`transaction()`](https://github.com/coral-xyz/anchor/blob/v0.30.1/ts/packages/anchor/src/program/namespace/methods.ts#L382) +[створює `Transaction`](https://github.com/coral-xyz/anchor/blob/v0.30.1/ts/packages/anchor/src/program/namespace/transaction.ts#L18-L26) +з вказаною інструкцією без відправки транзакції. + +```ts {12} /transaction()/1,2,4 +// Generate keypair for the new account +const newAccountKp = new Keypair(); + +const data = new BN(42); +const transaction = await program.methods + .initialize(data) + .accounts({ + newAccount: newAccountKp.publicKey, + signer: wallet.publicKey, + systemProgram: SystemProgram.programId, + }) + .transaction(); + +const transactionSignature = await connection.sendTransaction(transaction, [ + wallet.payer, + newAccountKp, +]); +``` + + + + +Метод +[`instruction()`](https://github.com/coral-xyz/anchor/blob/v0.30.1/ts/packages/anchor/src/program/namespace/methods.ts#L348) +[створює `TransactionInstruction`](https://github.com/coral-xyz/anchor/blob/v0.30.1/ts/packages/anchor/src/program/namespace/instruction.ts#L57-L61) +з вказаною інструкцією. Це корисно, якщо ви хочете вручну додати інструкцію до +транзакції та поєднати її з іншими інструкціями. + +```ts {12} /instruction()/ +// Generate keypair for the new account +const newAccountKp = new Keypair(); + +const data = new BN(42); +const instruction = await program.methods + .initialize(data) + .accounts({ + newAccount: newAccountKp.publicKey, + signer: wallet.publicKey, + systemProgram: SystemProgram.programId, + }) + .instruction(); + +const transaction = new Transaction().add(instruction); + +const transactionSignature = await connection.sendTransaction(transaction, [ + wallet.payer, + newAccountKp, +]); +``` + + + + +## Отримання облікових записів + +Клієнт `Program` спрощує процес отримання та десеріалізації облікових записів, +створених вашою програмою Anchor. + +Використовуйте `program.account`, за яким слідує назва типу облікового запису, +визначеного в IDL. Anchor надає кілька методів для отримання облікових записів. + + + + + +Використовуйте +[`all()`](https://github.com/coral-xyz/anchor/blob/v0.30.1/ts/packages/anchor/src/program/namespace/account.ts#L251) +для отримання всіх існуючих облікових записів для конкретного типу облікового +запису. + +```ts /all/ +const accounts = await program.account.newAccount.all(); +``` + + + + +Використовуйте `memcmp` (порівняння пам'яті) для фільтрації облікових записів, +дані яких відповідають конкретному значенню на вказаному зсуві. Для використання +`memcmp` необхідно розуміти байтову структуру поля даних для типу облікового +запису, який ви отримуєте. + +При обчисленні зсуву пам'ятайте, що перші 8 байтів у облікових записах, +створених програмою Anchor, зарезервовані для дискримінатора облікового запису. + +```ts /memcmp/ +const accounts = await program.account.newAccount.all([ + { + memcmp: { + offset: 8, + bytes: "", + }, + }, +]); +``` + + + + +Використовуйте +[`fetch()`](https://github.com/coral-xyz/anchor/blob/v0.30.1/ts/packages/anchor/src/program/namespace/account.ts#L165) +для отримання даних облікового запису для одного облікового запису. + +```ts /fetch/ +const account = await program.account.newAccount.fetch(ACCOUNT_ADDRESS); +``` + + + + +Використовуйте +[`fetchMultiple()`](https://github.com/coral-xyz/anchor/blob/v0.30.1/ts/packages/anchor/src/program/namespace/account.ts#L200) +для отримання даних облікових записів для кількох облікових записів, передавши +масив адрес облікових записів. + +```ts /fetchMultiple/ +const accounts = await program.account.newAccount.fetchMultiple([ + ACCOUNT_ADDRESS_ONE, + ACCOUNT_ADDRESS_TWO, +]); +``` + + + diff --git a/docs/locales/uk/programs/anchor/cpi.md b/docs/locales/uk/programs/anchor/cpi.md new file mode 100644 index 000000000..311a1444f --- /dev/null +++ b/docs/locales/uk/programs/anchor/cpi.md @@ -0,0 +1,548 @@ +--- +title: CPIs з Anchor +description: + Дізнайтеся, як реалізувати Cross Program Invocations (CPI) в програмах на + Anchor, що дозволяє взаємодіяти між різними програмами на Solana +sidebarLabel: CPIs з Anchor +sidebarSortOrder: 5 +--- + +[Cross Program Invocations (CPI)](/docs/core/cpi.md) означають процес, коли одна +програма викликає інструкції іншої програми, що дозволяє здійснювати композицію +програм на Solana. + +Цей розділ охоплює основи реалізації CPIs в програмі Anchor, використовуючи +інструкцію простого переказу SOL як практичний приклад. Після того, як ви +зрозумієте основи реалізації CPI, ви зможете застосувати ці ж концепції для +будь-якої інструкції. + +## Cross Program Invocations + +Розглянемо програму, яка реалізує CPI для інструкції переказу в System Program. +Ось приклад програми на +[Solana Playground](https://beta.solpg.io/66df2751cffcf4b13384d35a). + +Файл `lib.rs` містить одну інструкцію `sol_transfer`. Коли інструкція +`sol_transfer` в програмі Anchor викликається, програма внутрішньо викликає +інструкцію переказу з System Program. + +```rs filename="lib.rs" /sol_transfer/ /transfer/ {23} +use anchor_lang::prelude::*; +use anchor_lang::system_program::{transfer, Transfer}; + +declare_id!("9AvUNHjxscdkiKQ8tUn12QCMXtcnbR9BVGq3ULNzFMRi"); + +#[program] +pub mod cpi { + use super::*; + + pub fn sol_transfer(ctx: Context, amount: u64) -> Result<()> { + let from_pubkey = ctx.accounts.sender.to_account_info(); + let to_pubkey = ctx.accounts.recipient.to_account_info(); + let program_id = ctx.accounts.system_program.to_account_info(); + + let cpi_context = CpiContext::new( + program_id, + Transfer { + from: from_pubkey, + to: to_pubkey, + }, + ); + + transfer(cpi_context, amount)?; + Ok(()) + } +} + +#[derive(Accounts)] +pub struct SolTransfer<'info> { + #[account(mut)] + sender: Signer<'info>, + #[account(mut)] + recipient: SystemAccount<'info>, + system_program: Program<'info, System>, +} +``` + +Файл `cpi.test.ts` показує, як викликати інструкцію `sol_transfer` програми +Anchor і реєструє посилання на деталі транзакції на SolanaFM. + +```ts filename="cpi.test.ts" +it("SOL Transfer Anchor", async () => { + const transactionSignature = await program.methods + .solTransfer(new BN(transferAmount)) + .accounts({ + sender: sender.publicKey, + recipient: recipient.publicKey, + }) + .rpc(); + + console.log( + `\nTransaction Signature:` + + `https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`, + ); +}); +``` + +Ви можете побудувати, розгорнути та запустити тест для цього прикладу на +Playground, щоб переглянути деталі транзакції на +[SolanaFM explorer](https://solana.fm/). + +Деталі транзакції покажуть, що спочатку була викликана програма Anchor +(інструкція 1), яка потім викликає System Program (інструкція 1.1), що +призводить до успішного переказу SOL. + +![Деталі транзакції](/assets/docs/core/cpi/transaction-details.png) + +### Пояснення прикладу 1 + +Реалізація CPI слідує такому ж шаблону, як і створення інструкції для додавання +в транзакцію. Коли реалізуємо CPI, потрібно вказати ID програми, рахунки та дані +інструкції для викликаної інструкції. + +Інструкція переказу в System Program вимагає два рахунки: + +- `from`: Рахунок, що надсилає SOL. +- `to`: Рахунок, що отримує SOL. + +У прикладній програмі структура `SolTransfer` вказує рахунки, необхідні для +інструкції переказу. System Program також включена, оскільки CPI викликає System +Program. + +```rust /sender/ /recipient/ /system_program/ +#[derive(Accounts)] +pub struct SolTransfer<'info> { + #[account(mut)] + sender: Signer<'info>, // from account + #[account(mut)] + recipient: SystemAccount<'info>, // to account + system_program: Program<'info, System>, // program ID +} +``` + +Наступні вкладки представляють три підходи до реалізації Cross Program +Invocations (CPI), кожен з яких має різний рівень абстракції. Усі приклади є +функціонально еквівалентними. Основною метою є ілюстрація деталей реалізації +CPI. + + + + + +Інструкція `sol_transfer`, включена в прикладний код, показує типовий підхід до +побудови CPIs за допомогою фреймворку Anchor. + +Цей підхід передбачає створення +[`CpiContext`](https://docs.rs/anchor-lang/latest/anchor_lang/context/struct.CpiContext.html), +який містить `program_id` та рахунки, необхідні для викликаної інструкції, а +також допоміжну функцію (`transfer`) для виклику конкретної інструкції. + +```rust +use anchor_lang::system_program::{transfer, Transfer}; +``` + +```rust /cpi_context/ {14} +pub fn sol_transfer(ctx: Context, amount: u64) -> Result<()> { + let from_pubkey = ctx.accounts.sender.to_account_info(); + let to_pubkey = ctx.accounts.recipient.to_account_info(); + let program_id = ctx.accounts.system_program.to_account_info(); + + let cpi_context = CpiContext::new( + program_id, + Transfer { + from: from_pubkey, + to: to_pubkey, + }, + ); + + transfer(cpi_context, amount)?; + Ok(()) +} +``` + +Змінна `cpi_context` вказує ID програми (System Program) та рахунки (відправник +і отримувач), необхідні для інструкції переказу. + +```rust /program_id/ /from_pubkey/ /to_pubkey/ +let cpi_context = CpiContext::new( + program_id, + Transfer { + from: from_pubkey, + to: to_pubkey, + }, +); +``` + +Змінні `cpi_context` та `amount` передаються в функцію `transfer` для виконання +CPI, що викликає інструкцію переказу з System Program. + +```rust +transfer(cpi_context, amount)?; +``` + + + + +Цей приклад показує інший підхід до реалізації CPI за допомогою функції `invoke` +та +[`system_instruction::transfer`](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/sdk/program/src/system_instruction.rs#L881), +що зазвичай використовується в рідних програмах на Rust. + +Під капотом попередній приклад є абстракцією цієї реалізації. Нижче наведений +приклад є функціонально еквівалентним попередньому. + +```rust +use anchor_lang::solana_program::{program::invoke, system_instruction}; +``` + +```rust /instruction/1,3 {9} +pub fn sol_transfer(ctx: Context, amount: u64) -> Result<()> { + let from_pubkey = ctx.accounts.sender.to_account_info(); + let to_pubkey = ctx.accounts.recipient.to_account_info(); + let program_id = ctx.accounts.system_program.to_account_info(); + + let instruction = + &system_instruction::transfer(&from_pubkey.key(), &to_pubkey.key(), amount); + + invoke(instruction, &[from_pubkey, to_pubkey, program_id])?; + Ok(()) +} +``` + + + + +Ви також можете вручну створити інструкцію для передачі в функцію `invoke()`. Це +корисно, коли немає доступної бібліотеки, що допомагає побудувати інструкцію, +яку ви хочете викликати. Цей підхід вимагає вказати `AccountMeta` для інструкції +та правильно створити буфер даних інструкції. + +Інструкція `sol_transfer` нижче є вручну реалізованим CPI для інструкції +переказу в System Program. + +```rust /instruction/10,13 {28} +pub fn sol_transfer(ctx: Context, amount: u64) -> Result<()> { + let from_pubkey = ctx.accounts.sender.to_account_info(); + let to_pubkey = ctx.accounts.recipient.to_account_info(); + let program_id = ctx.accounts.system_program.to_account_info(); + + // Prepare instruction AccountMetas + let account_metas = vec![ + AccountMeta::new(from_pubkey.key(), true), + AccountMeta::new(to_pubkey.key(), false), + ]; + + // SOL transfer instruction discriminator + let instruction_discriminator: u32 = 2; + + // Prepare instruction data + let mut instruction_data = Vec::with_capacity(4 + 8); + instruction_data.extend_from_slice(&instruction_discriminator.to_le_bytes()); + instruction_data.extend_from_slice(&amount.to_le_bytes()); + + // Create instruction + let instruction = Instruction { + program_id: program_id.key(), + accounts: account_metas, + data: instruction_data, + }; + + // Invoke instruction + invoke(&instruction, &[from_pubkey, to_pubkey, program_id])?; + Ok(()) +} +``` + +Інструкція `sol_transfer` вище повторює цей +[приклад](/docs/core/transactions.md#manual-sol-transfer) вручну побудованої +інструкції переказу SOL. Вона слідує тому ж шаблону, що і створення +[інструкції](/docs/core/transactions.md#instruction) для додавання в транзакцію. + +При створенні інструкції на Rust використовуйте наступний синтаксис для вказівки +`AccountMeta` для кожного рахунку: + +```rust +AccountMeta::new(account1_pubkey, true), // writable, signer +AccountMeta::new(account2_pubkey, false), // writable, not signer +AccountMeta::new_readonly(account3_pubkey, false), // not writable, not signer +AccountMeta::new_readonly(account4_pubkey, true), // writable, signer +``` + + + + +Ось програмний приклад на +[Solana Playground](https://beta.solpg.io/github.com/ZYJLiu/doc-examples/tree/main/cpi), +який містить усі 3 приклади. + +## Cross Program Invocations з PDA підписами + +Далі розглянемо програму, яка реалізує CPI для інструкції переказу в System +Program, де відправником є Програма Походження Адреси (PDA), для якої програма +повинна "підписати" транзакцію. Ось приклад програми на +[Solana Playground](https://beta.solpg.io/66df2bd2cffcf4b13384d35b). + +Файл `lib.rs` містить наступну програму з єдиною інструкцією `sol_transfer`. + +```rust filename="lib.rs" +use anchor_lang::prelude::*; +use anchor_lang::system_program::{transfer, Transfer}; + +declare_id!("3455LkCS85a4aYmSeNbRrJsduNQfYRY82A7eCD3yQfyR"); + +#[program] +pub mod cpi { + use super::*; + + pub fn sol_transfer(ctx: Context, amount: u64) -> Result<()> { + let from_pubkey = ctx.accounts.pda_account.to_account_info(); + let to_pubkey = ctx.accounts.recipient.to_account_info(); + let program_id = ctx.accounts.system_program.to_account_info(); + + let seed = to_pubkey.key(); + let bump_seed = ctx.bumps.pda_account; + let signer_seeds: &[&[&[u8]]] = &[&[b"pda", seed.as_ref(), &[bump_seed]]]; + + let cpi_context = CpiContext::new( + program_id, + Transfer { + from: from_pubkey, + to: to_pubkey, + }, + ) + .with_signer(signer_seeds); + + transfer(cpi_context, amount)?; + Ok(()) + } +} + +#[derive(Accounts)] +pub struct SolTransfer<'info> { + #[account( + mut, + seeds = [b"pda", recipient.key().as_ref()], + bump, + )] + pda_account: SystemAccount<'info>, + #[account(mut)] + recipient: SystemAccount<'info>, + system_program: Program<'info, System>, +} +``` + +Файл `cpi.test.ts` показує, як викликати інструкцію `sol_transfer` програми +Anchor і реєструє посилання на деталі транзакції на SolanaFM. + +Він показує, як отримати PDA за допомогою насіння, вказаного в програмі: + +```ts /pda/ /wallet.publicKey/ +const [PDA] = PublicKey.findProgramAddressSync( + [Buffer.from("pda"), wallet.publicKey.toBuffer()], + program.programId, +); +``` + +Першим кроком у цьому прикладі є фінансування рахунку PDA за допомогою простого +переказу SOL з гаманця Playground. + +```ts filename="cpi.test.ts" +it("Fund PDA with SOL", async () => { + const transferInstruction = SystemProgram.transfer({ + fromPubkey: wallet.publicKey, + toPubkey: PDA, + lamports: transferAmount, + }); + + const transaction = new Transaction().add(transferInstruction); + + const transactionSignature = await sendAndConfirmTransaction( + connection, + transaction, + [wallet.payer], // signer + ); + + console.log( + `\nTransaction Signature:` + + `https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`, + ); +}); +``` + +Коли PDA буде фінансовано SOL, викликається інструкція `sol_transfer`. Ця +інструкція переказує SOL з рахунку PDA назад на рахунок `wallet` через CPI до +System Program, що "підписується" програмою. + +```ts +it("SOL Transfer with PDA signer", async () => { + const transactionSignature = await program.methods + .solTransfer(new BN(transferAmount)) + .accounts({ + pdaAccount: PDA, + recipient: wallet.publicKey, + }) + .rpc(); + + console.log( + `\nTransaction Signature: https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`, + ); +}); +``` + +Ви можете побудувати, розгорнути та запустити тест, щоб переглянути деталі +транзакції на [SolanaFM explorer](https://solana.fm/). + +Деталі транзакції покажуть, що спочатку була викликана користувацька програма +(інструкція 1), яка потім викликає System Program (інструкція 1.1), що +призводить до успішного переказу SOL. + +![Деталі транзакції](/assets/docs/core/cpi/transaction-details-pda.png) + +### Пояснення прикладу 2 + +У прикладному коді структура `SolTransfer` вказує рахунки, необхідні для +інструкції переказу. + +Відправником є PDA, для якого програма повинна підписати транзакцію. `seeds`, +які використовуються для отримання адреси для `pda_account`, включають зашитий +рядок "pda" та адресу рахунку `recipient`. Це означає, що адреса для +`pda_account` є унікальною для кожного `recipient`. + +```rust /pda_account/ /recipient/2 /system_program/ +#[derive(Accounts)] +pub struct SolTransfer<'info> { + #[account( + mut, + seeds = [b"pda", recipient.key().as_ref()], + bump, + )] + pda_account: SystemAccount<'info>, + #[account(mut)] + recipient: SystemAccount<'info>, + system_program: Program<'info, System>, +} +``` + +Еквівалент на Javascript для отримання PDA включений у тестовий файл. + +```ts /pda/ /wallet.publicKey/ +const [PDA] = PublicKey.findProgramAddressSync( + [Buffer.from("pda"), wallet.publicKey.toBuffer()], + program.programId, +); +``` + +Наступні вкладки представляють два підходи до реалізації Cross Program +Invocations (CPI), кожен з яких має різний рівень абстракції. Обидва приклади є +функціонально еквівалентними. Основною метою є ілюстрація деталей реалізації +CPI. + + + + + +Інструкція `sol_transfer`, включена в прикладний код, показує типовий підхід до +побудови CPIs за допомогою фреймворку Anchor. + +Цей підхід передбачає створення +[`CpiContext`](https://docs.rs/anchor-lang/latest/anchor_lang/context/struct.CpiContext.html), +який містить `program_id` та рахунки, необхідні для викликаної інструкції, а +також допоміжну функцію (`transfer`) для виклику конкретної інструкції. + +```rust /cpi_context/ {19} +pub fn sol_transfer(ctx: Context, amount: u64) -> Result<()> { + let from_pubkey = ctx.accounts.pda_account.to_account_info(); + let to_pubkey = ctx.accounts.recipient.to_account_info(); + let program_id = ctx.accounts.system_program.to_account_info(); + + let seed = to_pubkey.key(); + let bump_seed = ctx.bumps.pda_account; + let signer_seeds: &[&[&[u8]]] = &[&[b"pda", seed.as_ref(), &[bump_seed]]]; + + let cpi_context = CpiContext::new( + program_id, + Transfer { + from: from_pubkey, + to: to_pubkey, + }, + ) + .with_signer(signer_seeds); + + transfer(cpi_context, amount)?; + Ok(()) +} +``` + +При підписанні за допомогою PDA, насіння та bump seed включаються в +`cpi_context` як `signer_seeds` за допомогою `with_signer()`. Bump seed для PDA +можна отримати за допомогою `ctx.bumps`, після чого вказується ім'я рахунку PDA. + +```rust /signer_seeds/ /bump_seed/ {3} +let seed = to_pubkey.key(); +let bump_seed = ctx.bumps.pda_account; +let signer_seeds: &[&[&[u8]]] = &[&[b"pda", seed.as_ref(), &[bump_seed]]]; + +let cpi_context = CpiContext::new( + program_id, + Transfer { + from: from_pubkey, + to: to_pubkey, + }, +) +.with_signer(signer_seeds); +``` + +Змінні `cpi_context` та `amount` передаються в функцію `transfer` для виконання +CPI. + +```rust +transfer(cpi_context, amount)?; +``` + +Коли обробляється CPI, середовище виконання Solana перевіряє, чи правильно +наведені насіння та ID програми викликача для отримання дійсного PDA. Потім PDA +додається як підписант під час виклику. Цей механізм дозволяє програмам +підписувати PDA, які отримані з їхнього ID програми. + + + + +Під капотом попередній приклад є обгорткою для функції `invoke_signed()`, яка +використовує +[`system_instruction::transfer`](https://github.com/solana-labs/solana/blob/27eff8408b7223bb3c4ab70523f8a8dca3ca6645/sdk/program/src/system_instruction.rs#L881) +для побудови інструкції. + +Цей приклад показує, як використовувати функцію `invoke_signed()`, щоб зробити +CPI підписаним PDA. + +```rust +use anchor_lang::solana_program::{program::invoke_signed, system_instruction}; +``` + +```rust /instruction/1,3 {13} +pub fn sol_transfer(ctx: Context, amount: u64) -> Result<()> { + let from_pubkey = ctx.accounts.pda_account.to_account_info(); + let to_pubkey = ctx.accounts.recipient.to_account_info(); + let program_id = ctx.accounts.system_program.to_account_info(); + + let seed = to_pubkey.key(); + let bump_seed = ctx.bumps.pda_account; + let signer_seeds: &[&[&[u8]]] = &[&[b"pda", seed.as_ref(), &[bump_seed]]]; + + let instruction = + &system_instruction::transfer(&from_pubkey.key(), &to_pubkey.key(), amount); + + invoke_signed(instruction, &[from_pubkey, to_pubkey, program_id], signer_seeds)?; + Ok(()) +} +``` + +Ця реалізація функціонально еквівалентна попередньому прикладу. `signer_seeds` +передаються в функцію `invoke_signed`. + + + + +Ось програмний приклад на +[Solana Playground](https://beta.solpg.io/github.com/ZYJLiu/doc-examples/tree/main/cpi-pda), +який містить обидва приклади. diff --git a/docs/locales/uk/programs/anchor/idl.md b/docs/locales/uk/programs/anchor/idl.md new file mode 100644 index 000000000..080f030d6 --- /dev/null +++ b/docs/locales/uk/programs/anchor/idl.md @@ -0,0 +1,516 @@ +--- +title: Файл IDL +description: + Дізнайтесь про файл Interface Definition Language (IDL) в Anchor, його + призначення, переваги та те, як він спрощує взаємодію програми з клієнтами +sidebarLabel: Файл IDL +sidebarSortOrder: 2 +--- + +Файл Interface Definition Language (IDL) надає стандартизований JSON-файл, який +описує інструкції та рахунки програми. Цей файл спрощує процес інтеграції вашої +програми на блокчейні з клієнтськими додатками. + +Основні переваги IDL: + +- Стандартизація: Надає послідовний формат для опису інструкцій та рахунків + програми +- Генерація клієнта: Використовується для генерації коду клієнта для взаємодії з + програмою + +Команда `anchor build` генерує файл IDL, який знаходиться за адресою +`/target/idl/.json`. + +Нижче наведені фрагменти коду, що показують, як програма, IDL та клієнт +взаємопов'язані. + +## Інструкції програми + +Масив `instructions` у файлі IDL безпосередньо відповідає інструкціям, +визначеним у вашій програмі. Він вказує на необхідні рахунки та параметри для +кожної інструкції. + + + + + +Наведена програма включає інструкцію `initialize`, що вказує на рахунки та +параметри, які вона потребує. + +```rust {8-12, 15-22} +use anchor_lang::prelude::*; + +declare_id!("BYFW1vhC1ohxwRbYoLbAWs86STa25i9sD5uEusVjTYNd"); + +#[program] +mod hello_anchor { + use super::*; + pub fn initialize(ctx: Context, data: u64) -> Result<()> { + ctx.accounts.new_account.data = data; + msg!("Changed data to: {}!", data); + Ok(()) + } +} + +#[derive(Accounts)] +pub struct Initialize<'info> { + #[account(init, payer = signer, space = 8 + 8)] + pub new_account: Account<'info, NewAccount>, + #[account(mut)] + pub signer: Signer<'info>, + pub system_program: Program<'info, System>, +} + +#[account] +pub struct NewAccount { + data: u64, +} +``` + + + + +Згенерований файл IDL включає інструкцію в стандартизованому форматі JSON, +включаючи її ім'я, рахунки, аргументи та дискримінатор. + +```json filename="JSON" {11-12, 14-27, 30-33} +{ + "address": "BYFW1vhC1ohxwRbYoLbAWs86STa25i9sD5uEusVjTYNd", + "metadata": { + "name": "hello_anchor", + "version": "0.1.0", + "spec": "0.1.0", + "description": "Created with Anchor" + }, + "instructions": [ + { + "name": "initialize", + "discriminator": [175, 175, 109, 31, 13, 152, 155, 237], + "accounts": [ + { + "name": "new_account", + "writable": true, + "signer": true + }, + { + "name": "signer", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "data", + "type": "u64" + } + ] + } + ], + "accounts": [ + { + "name": "NewAccount", + "discriminator": [176, 95, 4, 118, 91, 177, 125, 232] + } + ], + "types": [ + { + "name": "NewAccount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "data", + "type": "u64" + } + ] + } + } + ] +} +``` + + + + +Файл IDL потім використовується для генерації клієнта для взаємодії з програмою, +спрощуючи процес виклику інструкції програми. + +```ts {19-26} +import * as anchor from "@coral-xyz/anchor"; +import { Program, BN } from "@coral-xyz/anchor"; +import { HelloAnchor } from "../target/types/hello_anchor"; +import { Keypair } from "@solana/web3.js"; +import assert from "assert"; + +describe("hello_anchor", () => { + const provider = anchor.AnchorProvider.env(); + anchor.setProvider(provider); + const wallet = provider.wallet as anchor.Wallet; + const program = anchor.workspace.HelloAnchor as Program; + + it("initialize", async () => { + // Generate keypair for the new account + const newAccountKp = new Keypair(); + + // Send transaction + const data = new BN(42); + const transactionSignature = await program.methods + .initialize(data) + .accounts({ + newAccount: newAccountKp.publicKey, + signer: wallet.publicKey, + }) + .signers([newAccountKp]) + .rpc(); + + // Fetch the created account + const newAccount = await program.account.newAccount.fetch( + newAccountKp.publicKey, + ); + + console.log("Transaction signature: ", transactionSignature); + console.log("On-chain data is:", newAccount.data.toString()); + assert(data.eq(newAccount.data)); + }); +}); +``` + + + + +## Рахунки програми + +Масив `accounts` у файлі IDL відповідає структурам у програмі, позначеним +макросом `#[account]`. Ці структури визначають дані, які зберігаються в +рахунках, створених програмою. + + + + + +Наведена програма визначає структуру `NewAccount` з одним полем `data` типу +`u64`. + +```rust {24-27} +use anchor_lang::prelude::*; + +declare_id!("BYFW1vhC1ohxwRbYoLbAWs86STa25i9sD5uEusVjTYNd"); + +#[program] +mod hello_anchor { + use super::*; + pub fn initialize(ctx: Context, data: u64) -> Result<()> { + ctx.accounts.new_account.data = data; + msg!("Changed data to: {}!", data); + Ok(()) + } +} + +#[derive(Accounts)] +pub struct Initialize<'info> { + #[account(init, payer = signer, space = 8 + 8)] + pub new_account: Account<'info, NewAccount>, + #[account(mut)] + pub signer: Signer<'info>, + pub system_program: Program<'info, System>, +} + +#[account] +pub struct NewAccount { + data: u64, +} +``` + + + + +Згенерований файл IDL включає рахунок у стандартизованому форматі JSON, +включаючи його ім'я, дискримінатор та поля. + +```json filename="JSON" {39-40, 45-54} +{ + "address": "BYFW1vhC1ohxwRbYoLbAWs86STa25i9sD5uEusVjTYNd", + "metadata": { + "name": "hello_anchor", + "version": "0.1.0", + "spec": "0.1.0", + "description": "Created with Anchor" + }, + "instructions": [ + { + "name": "initialize", + "discriminator": [175, 175, 109, 31, 13, 152, 155, 237], + "accounts": [ + { + "name": "new_account", + "writable": true, + "signer": true + }, + { + "name": "signer", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "data", + "type": "u64" + } + ] + } + ], + "accounts": [ + { + "name": "NewAccount", + "discriminator": [176, 95, 4, 118, 91, 177, 125, 232] + } + ], + "types": [ + { + "name": "NewAccount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "data", + "type": "u64" + } + ] + } + } + ] +} +``` + + + + +Файл IDL потім використовується для генерації клієнта для взаємодії з програмою, +спрощуючи процес отримання та десеріалізації даних рахунку. + +```ts {29-31} +import * as anchor from "@coral-xyz/anchor"; +import { Program, BN } from "@coral-xyz/anchor"; +import { HelloAnchor } from "../target/types/hello_anchor"; +import { Keypair } from "@solana/web3.js"; +import assert from "assert"; + +describe("hello_anchor", () => { + const provider = anchor.AnchorProvider.env(); + anchor.setProvider(provider); + const wallet = provider.wallet as anchor.Wallet; + const program = anchor.workspace.HelloAnchor as Program; + + it("initialize", async () => { + // Generate keypair for the new account + const newAccountKp = new Keypair(); + + // Send transaction + const data = new BN(42); + const transactionSignature = await program.methods + .initialize(data) + .accounts({ + newAccount: newAccountKp.publicKey, + signer: wallet.publicKey, + }) + .signers([newAccountKp]) + .rpc(); + + // Fetch the created account + const newAccount = await program.account.newAccount.fetch( + newAccountKp.publicKey, + ); + + console.log("Transaction signature: ", transactionSignature); + console.log("On-chain data is:", newAccount.data.toString()); + assert(data.eq(newAccount.data)); + }); +}); +``` + + + + +## Дискримінатори + +Anchor призначає унікальний 8-байтовий дискримінатор для кожної інструкції та +типу рахунку в програмі. Ці дискримінатори служать як ідентифікатори для +відрізнення різних інструкцій або типів рахунків. + +Дискримінатор генерується за допомогою перших 8 байтів хешу Sha256 префікса, +поєднаного з ім'ям інструкції або рахунку. Починаючи з версії Anchor v0.30, ці +дискримінатори включені в файл IDL. + +Зверніть увагу, що при роботі з Anchor, вам зазвичай не потрібно взаємодіяти +безпосередньо з цими дискримінаторами. Цей розділ надає контекст щодо того, як +генерується і використовується дискримінатор. + + + + + +Дискримінатор інструкції використовується програмою для визначення, яку +конкретну інструкцію виконати при виклику. + +Коли інструкція програми Anchor викликається, дискримінатор включається як перші +8 байтів даних інструкції. Це робиться автоматично клієнтом Anchor. + +```json filename="IDL" {4} + "instructions": [ + { + "name": "initialize", + "discriminator": [175, 175, 109, 31, 13, 152, 155, 237], + ... + } + ] +``` + +Дискримінатор для інструкції — це перші 8 байтів хешу Sha256 префікса `global` +плюс ім'я інструкції. + +Наприклад: + +``` +sha256("global:initialize") +``` + +Hexadecimal output: + +``` +af af 6d 1f 0d 98 9b ed d4 6a 95 07 32 81 ad c2 1b b5 e0 e1 d7 73 b2 fb bd 7a b5 04 cd d4 aa 30 +``` + +The first 8 bytes are used as the discriminator for the instruction. + +``` +af = 175 +af = 175 +6d = 109 +1f = 31 +0d = 13 +98 = 152 +9b = 155 +ed = 237 +``` + +Реалізацію генерації дискримінатора ви можете знайти в кодовій базі Anchor +[тут](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/syn/src/codegen/program/common.rs#L5-L19), +яка використовується +[тут](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/syn/src/codegen/program/instruction.rs#L27). + + + + +Дискримінатор рахунку використовується для ідентифікації конкретного типу +рахунку при десеріалізації даних з ланцюга та встановлюється при створенні +рахунку. + +```json filename="IDL" {4} + "accounts": [ + { + "name": "NewAccount", + "discriminator": [176, 95, 4, 118, 91, 177, 125, 232] + } + ] +``` + +Дискримінатор для рахунку — це перші 8 байтів хешу Sha256 префікса `account` +плюс ім'я рахунку. + +Наприклад: + +``` +sha256("account:NewAccount") +``` + +Hexadecimal output: + +``` +b0 5f 04 76 5b b1 7d e8 a1 93 57 2a d3 5e b1 ae e5 f0 69 e2 09 7e 5c d2 64 56 55 2a cb 4a e9 57 +``` + +Перші 8 байтів використовуються як дискримінатор для рахунку. + +``` +b0 = 176 +5f = 95 +04 = 4 +76 = 118 +5b = 91 +b1 = 177 +7d = 125 +e8 = 232 +``` + +Реалізацію генерації дискримінатора ви можете знайти в кодовій базі Anchor +[тут](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/attribute/account/src/lib.rs#L101-L117). + +Зверніть увагу, що різні програми, які використовують однакові імена рахунків, +генеруватимуть той самий дискримінатор. При десеріалізації даних рахунків +програми Anchor також перевірятимуть, що рахунок належить очікуваній програмі +для заданого типу рахунку. + + + + +Дискримінатор події використовується для ідентифікації конкретного типу події +при десеріалізації даних з ланцюга при емісії події. + +```json filename="IDL" {4} + "events": [ + { + "name": "NewEvent", + "discriminator": [113, 21, 185, 70, 164, 99, 232, 201] + } + ] +``` + +Дискримінатор для події — це перші 8 байтів хешу Sha256 префікса `event` плюс +ім'я події. + +Наприклад: + +``` +sha256("event:NewEvent") +``` + +Hexadecimal output: + +``` +71 15 b9 46 a4 63 e8 c9 2a 3c 4d 83 87 16 cd 9b 66 28 cb e2 cb 7c 5d 70 59 f3 42 2b dc 35 03 53 +``` + +Перші 8 байтів використовуються як дискримінатор для рахунку. + +Перетворення з шістнадцяткового в десятковий дає нам: + +``` +71 = 113 +15 = 21 +b9 = 185 +46 = 70 +a4 = 164 +63 = 99 +e8 = 232 +c9 = 201 +``` + +Реалізацію генерації дискримінатора ви можете знайти в кодовій базі Anchor +[тут](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/attribute/event/src/lib.rs#L23-L27). + +Зверніть увагу, що різні програми, які використовують однакові імена подій, +генеруватимуть той самий дискримінатор. При десеріалізації даних подій програми +Anchor також перевірятимуть, що подія належить очікуваній програмі для заданого +типу події. + + + diff --git a/docs/locales/uk/programs/anchor/index.md b/docs/locales/uk/programs/anchor/index.md new file mode 100644 index 000000000..169686979 --- /dev/null +++ b/docs/locales/uk/programs/anchor/index.md @@ -0,0 +1,387 @@ +--- +title: Початок роботи з Anchor +description: + Дізнайтесь, як будувати програми для Solana за допомогою фреймворку Anchor. + Цей детальний посібник охоплює створення, збірку, тестування та розгортання + смарт-контрактів Solana з використанням Anchor. +sidebarLabel: Фреймворк Anchor +sidebarSortOrder: 0 +altRoutes: + - /docs/programs/debugging + - /docs/programs/lang-c + - /docs/programs/overview +--- + +Фреймворк Anchor — це інструмент, який спрощує процес створення програм для +Solana. Неважливо, чи ви новачок у блокчейн-розробці, чи досвідчений програміст, +Anchor спрощує процес написання, тестування та розгортання програм для Solana. + +У цьому розділі ми розглянемо: + +- Створення нового проекту Anchor +- Збірка та тестування вашої програми +- Розгортання на кластерах Solana +- Розуміння структури файлів проекту + +## Попередні вимоги + +Для детальних інструкцій по установці відвідайте сторінку +[встановлення](/docs/intro/installation). + +Перед тим, як почати, переконайтесь, що у вас встановлено наступне: + +- Rust: Мова програмування для створення програм для Solana. +- Solana CLI: Інструмент командного рядка для розробки на Solana. +- Anchor CLI: Інструмент командного рядка для фреймворку Anchor. + +Щоб перевірити встановлення Anchor CLI, відкрийте термінал і виконайте: + +```shell filename="Terminal" +anchor --version +``` + +Очікуваний результат: + +```shell filename="Terminal" +anchor-cli 0.30.1 +``` + +## Початок роботи + +Цей розділ охоплює основні кроки для створення, зборки та тестування вашої +першої локальної програми на Anchor. + + + +### Створення нового проекту + +Щоб почати новий проект, використовуйте команду `anchor init`, після якої +вкажіть назву вашого проекту. Ця команда створює нову директорію з вказаним +ім'ям і налаштовує стандартну програму та тестовий файл. + +```shell filename="Terminal" +anchor init my-project +``` + +Перейдіть до нової директорії проекту та відкрийте її у вашому редакторі коду. + +```shell filename="Terminal" copy +cd my-project +``` + +Стандартна програма Anchor знаходиться за адресою +`programs/my-project/src/lib.rs`. + + + + +Значення в макросі `declare_id!` є ID програми, унікальним ідентифікатором для +вашої програми. + +За замовчуванням це публічний ключ ключової пари, згенерованої в +`/target/deploy/my_project-keypair.json`. + +```rs filename="lib.rs" +use anchor_lang::prelude::*; + +declare_id!("3ynNB373Q3VAzKp7m4x238po36hjAGFXFJB4ybN2iTyg"); + +#[program] +pub mod my_project { + use super::*; + + pub fn initialize(ctx: Context) -> Result<()> { + msg!("Greetings from: {:?}", ctx.program_id); + Ok(()) + } +} + +#[derive(Accounts)] +pub struct Initialize {} +``` + + + + +Стандартний тестовий файл TypeScript знаходиться за адресою +`/tests/my-project.ts`. + + + + +Цей файл демонструє, як викликати інструкцію `initialize` стандартної програми в +TypeScript. + +```ts filename="my-project.ts" +import * as anchor from "@coral-xyz/anchor"; +import { Program } from "@coral-xyz/anchor"; +import { MyProject } from "../target/types/my_project"; + +describe("my-project", () => { + // Configure the client to use the local cluster. + anchor.setProvider(anchor.AnchorProvider.env()); + + const program = anchor.workspace.MyProject as Program; + + it("Is initialized!", async () => { + // Add your test here. + const tx = await program.methods.initialize().rpc(); + console.log("Your transaction signature", tx); + }); +}); +``` + + + + +Якщо ви віддаєте перевагу Rust для тестування, ініціалізуйте свій проект за +допомогою прапорця `--test-template rust`. + +```shell +anchor init --test-template rust my-project +``` + +Тестовий файл Rust буде знаходитися за адресою `/tests/src/test_initialize.rs`. + + + + +```rust filename="test_initialize.rs" +use std::str::FromStr; + +use anchor_client::{ + solana_sdk::{ + commitment_config::CommitmentConfig, pubkey::Pubkey, signature::read_keypair_file, + }, + Client, Cluster, +}; + +#[test] +fn test_initialize() { + let program_id = "3ynNB373Q3VAzKp7m4x238po36hjAGFXFJB4ybN2iTyg"; + let anchor_wallet = std::env::var("ANCHOR_WALLET").unwrap(); + let payer = read_keypair_file(&anchor_wallet).unwrap(); + + let client = Client::new_with_options(Cluster::Localnet, &payer, CommitmentConfig::confirmed()); + let program_id = Pubkey::from_str(program_id).unwrap(); + let program = client.program(program_id).unwrap(); + + let tx = program + .request() + .accounts(my_program::accounts::Initialize {}) + .args(my_program::instruction::Initialize {}) + .send() + .expect(""); + + println!("Your transaction signature {}", tx); +} +``` + + + + +### Збірка програми + +Зібрати програму можна, виконавши команду `anchor build`. + +```shell filename="Terminal" copy +anchor build +``` + +Зкомпільована програма буде знаходитися за адресою +`/target/deploy/my_project.so`. Вміст цього файлу буде збережено в мережі Solana +(як виконуваний акаунт) під час розгортання вашої програми. + +### Тестування програми + +Для тестування програми виконайте команду `anchor test`. + +```shell filename="Terminal" copy +anchor test +``` + +За замовчуванням конфігураційний файл `Anchor.toml` вказує на кластер +`localnet`. При розробці на `localnet`, команда `anchor test` автоматично: + +1. Запускає локальний валідатор Solana +2. Створює та розгортає вашу програму на локальному кластері +3. Виконує тести з папки `tests` +4. Зупиняє локальний валідатор Solana + +Альтернативно, ви можете вручну запустити локальний валідатор Solana та +виконувати тести проти нього. Це корисно, якщо ви хочете, щоб валідатор +працював, поки ви працюєте над програмою. Це дозволяє вам перевіряти акаунти та +журнали транзакцій на +[Solana Explorer](https://explorer.solana.com/?cluster=custom) під час розробки +локально. + +Відкрийте новий термінал і запустіть локальний валідатор Solana, виконуючи +команду `solana-test-validator`. + +```shell filename="Terminal" copy +solana-test-validator +``` + +У окремому терміналі виконайте тести проти локального кластера. Використовуйте +прапорець `--skip-local-validator`, щоб пропустити запуск локального валідатора, +оскільки він уже працює. + +```shell filename="Terminal" copy +anchor test --skip-local-validator +``` + +### Розгортання на Devnet + +За замовчуванням конфігураційний файл `Anchor.toml` у проекті Anchor вказує на +кластер localnet. + +```toml filename="Anchor.toml" {14} +[toolchain] + +[features] +resolution = true +skip-lint = false + +[programs.localnet] +my_program = "3ynNB373Q3VAzKp7m4x238po36hjAGFXFJB4ybN2iTyg" + +[registry] +url = "https://api.apr.dev" + +[provider] +cluster = "Localnet" +wallet = "~/.config/solana/id.json" + +[scripts] +test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" +``` + +Щоб розгорнути вашу програму на devnet, змініть значення `cluster` на `Devnet`. +Зверніть увагу, що для цього ваш гаманець повинен мати достатньо SOL на Devnet +для покриття вартості розгортання. + +```diff +-cluster = "Localnet" ++cluster = "Devnet" +``` + +```toml filename="Anchor.toml" +[provider] +cluster = "Devnet" +wallet = "~/.config/solana/id.json" +``` + +Тепер, коли ви виконаєте команду `anchor deploy`, ваша програма буде розгорнута +на кластері devnet. Команда `anchor test` також використовуватиме кластер, +вказаний у файлі `Anchor.toml`. + +```shell +anchor deploy +``` + +Щоб розгорнути на mainnet, просто оновіть файл `Anchor.toml`, вказавши кластер +mainnet. + +```toml filename="Anchor.toml" +[provider] +cluster = "Mainnet" +wallet = "~/.config/solana/id.json" +``` + +### Оновлення програми + +Програми Solana можна оновити, повторно розгорнувши програму з тим самим ID +програми. + +Щоб оновити програму, просто внесіть зміни в код вашої програми і виконайте +команду `anchor build` для генерації оновленого файлу `.so`. + +```shell +anchor build +``` + +Потім виконайте команду `anchor deploy`, щоб повторно розгорнути оновлену +програму. + +```shell +anchor deploy +``` + +### Закриття програми + +Щоб повернути SOL, виділені на акаунт програми, ви можете закрити вашу програму +Solana. + +Для закриття програми використовуйте команду +`solana program close `. Наприклад: + +```shell +solana program close 3ynNB373Q3VAzKp7m4x238po36hjAGFXFJB4ybN2iTyg --bypass-warning +``` + +Зверніть увагу, що після закриття програми, ID програми не можна буде +використовувати для розгортання нової програми. + + + +## Структура файлів проекту + +Нижче наведено огляд стандартної структури файлів у робочому просторі Anchor: + +``` +. +├── .anchor +│ └── program-logs +├── app +├── migrations +├── programs +│ └── [project-name] +│ └── src +│ ├── lib.rs +│ ├── Cargo.toml +│ └── Xargo.toml +├── target +│ ├── deploy +│ │ └── [project-name]-keypair.json +│ ├── idl +│ │ └── [project-name].json +│ └── types +│ └── [project-name].ts +├── tests +│ └── [project-name].ts +├── Anchor.toml +├── Cargo.toml +└── package.json +``` + +### Папка Programs + +Папка `/programs` містить програми Anchor вашого проекту. Один робочий простір +може містити кілька програм. + +### Папка Tests + +Папка `/tests` містить тестові файли для вашого проекту. Стандартний тестовий +файл створюється автоматично під час створення вашого проекту. + +### Папка Target + +Папка `/target` містить результати збірки. Основні підпапки включають: + +- `/deploy`: Містить ключову пару та бінарний файл програми для ваших програм. +- `/idl`: Містить JSON IDL для ваших програм. +- `/types`: Містить TypeScript тип для IDL. + +### Файл Anchor.toml + +Файл `Anchor.toml` налаштовує параметри робочого простору для вашого проекту. + +### Папка .anchor + +Містить файл `program-logs`, що містить журнали транзакцій з останнього +виконання тестових файлів. + +### Папка App + +Папка `/app` є порожньою і може бути опційно використана для вашого +фронтенд-коду. diff --git a/docs/locales/uk/programs/anchor/pda.md b/docs/locales/uk/programs/anchor/pda.md new file mode 100644 index 000000000..5b80e71a7 --- /dev/null +++ b/docs/locales/uk/programs/anchor/pda.md @@ -0,0 +1,331 @@ +--- +title: PDAs з Anchor +description: + Дізнайтеся, як використовувати Program Derived Addresses (PDA) в програмах + Anchor, використовуючи обмеження та реалізуючи поширені шаблони PDA +sidebarLabel: PDAs з Anchor +sidebarSortOrder: 4 +--- + +[Program Derived Addresses (PDA)](/docs/core/pda) — це функція розробки на +Solana, яка дозволяє створювати унікальну адресу, що отримується детерміновано з +попередньо визначених вхідних значень (насіння) та ID програми. + +Цей розділ охоплює базові приклади використання PDA в програмі Anchor. + +## Обмеження Anchor для PDA + +При використанні PDA в програмі Anchor, зазвичай використовуються обмеження +акаунтів Anchor для визначення насіння, що використовуються для отримання PDA. +Ці обмеження служать як перевірки безпеки, щоб переконатися, що правильна адреса +була отримана. + +Обмеження, які використовуються для визначення насіння PDA, включають: + +- `seeds`: Масив необов'язкових насінь, що використовуються для отримання PDA. + Насіння можуть бути статичними значеннями або динамічними посиланнями на дані + акаунтів. +- `bump`: Bump seed, що використовується для отримання PDA. Використовується для + забезпечення того, щоб адреса не потрапляла на криву Ed25519 і була дійсним + PDA. +- `seeds::program` - (Необов'язково) ID програми, що використовується для + отримання адреси PDA. Це обмеження використовується лише для отримання PDA, де + ID програми не є поточною програмою. + +Обмеження `seeds` та `bump` повинні використовуватися разом. + +### Приклади використання + +Нижче наведені приклади, що демонструють, як використовувати обмеження PDA в +програмі Anchor. + + + + + +Обмеження `seeds` визначає необов'язкові значення, що використовуються для +отримання PDA. + +#### Без необов'язкових сідів + +- Використовуйте порожній масив `[]`, щоб визначити PDA без необов'язкових + насінь. + +```rs +#[derive(Accounts)] +pub struct InstructionAccounts<'info> { + #[account( + seeds = [], + bump, + )] + pub pda_account: SystemAccount<'info>, +} +``` + +#### Одне статичне насіння + +- Вкажіть необов'язкові насіння в обмеженні `seeds`. + +```rs +#[derive(Accounts)] +pub struct InstructionAccounts<'info> { + #[account( + seeds = [b"hello_world"], + bump, + )] + pub pda_account: SystemAccount<'info>, +} +``` + +#### Кілька насінь та посилань на акаунти + +- Можна вказати кілька насінь в обмеженні `seeds`. Обмеження `seeds` також може + посилатися на інші адреси акаунтів або дані акаунтів. + +```rs +#[derive(Accounts)] +pub struct InstructionAccounts<'info> { + pub signer: Signer<'info>, + #[account( + seeds = [b"hello_world", signer.key().as_ref()], + bump, + )] + pub pda_account: SystemAccount<'info>, +} +``` + +Приклад вище використовує як статичне насіння (`b"hello_world"`), так і +динамічне насіння (публічний ключ підписанта). + + + + +Обмеження `bump` визначає bump seed, що використовується для отримання PDA. + +#### Автоматичний розрахунок Bump + +При використанні обмеження `bump` без вказаного значення, bump автоматично +вираховується щоразу, коли викликається інструкція. + +```rs +#[derive(Accounts)] +pub struct InstructionAccounts<'info> { + #[account( + seeds = [b"hello_world"], + bump, + )] + pub pda_account: SystemAccount<'info>, +} +``` + +#### Вказати значення Bump + +Ви можете явно вказати значення bump, що корисно для оптимізації використання +обчислювальних одиниць. Це передбачає, що акаунт PDA вже був створений і bump +seed зберігається як поле в існуючому акаунті. + +```rs +#[derive(Accounts)] +pub struct InstructionAccounts<'info> { + #[account( + seeds = [b"hello_world"], + bump = pda_account.bump_seed, + )] + pub pda_account: Account<'info, CustomAccount>, +} + +#[account] +pub struct CustomAccount { + pub bump_seed: u8, +} +``` + +Зберігаючи значення bump у даних акаунту, програма не потребує його повторного +обчислення, що дозволяє заощадити обчислювальні одиниці. Збережене значення bump +може бути збережено в самому акаунті або в іншому акаунті. + + + + +Обмеження `seeds::program` визначає ID програми, що використовується для +отримання PDA. Це обмеження використовується лише при отриманні PDA з іншої +програми. + +Використовуйте це обмеження, коли ваша інструкція повинна взаємодіяти з +акаунтами PDA, створеними іншою програмою. + +```rs +#[derive(Accounts)] +pub struct InstructionAccounts<'info> { + #[account( + seeds = [b"hello_world"], + bump, + seeds::program = other_program.key(), + )] + pub pda_account: SystemAccount<'info>, + pub other_program: Program<'info, OtherProgram>, +} +``` + + + + +Обмеження `init` зазвичай використовується разом з `seeds` та `bump` для +створення нового акаунту з адресою, яка є PDA. Під капотом обмеження `init` +викликає System Program для створення акаунту. + +```rs +#[derive(Accounts)] +pub struct InstructionAccounts<'info> { + #[account(mut)] + pub signer: Signer<'info>, + #[account( + init, + seeds = [b"hello_world", signer.key().as_ref()], + bump, + payer = signer, + space = 8 + 1, + )] + pub pda_account: Account<'info, CustomAccount>, + pub system_program: Program<'info, System>, +} + +#[account] +pub struct CustomAccount { + pub bump_seed: u8, +} +``` + + + + +## Насіння PDA в IDL + +Насіння Program Derived Address (PDA), визначені в обмеженні `seeds`, включені в +IDL файл програми. Це дозволяє клієнту Anchor автоматично вирішувати акаунти, +використовуючи ці насіння під час побудови інструкцій. + +Наведений нижче приклад показує взаємозв'язок між програмою, IDL та клієнтом. + + + + + +Програма нижче визначає `pda_account`, використовуючи статичне насіння +(`b"hello_world"`) та публічний ключ підписанта як динамічне насіння. + +```rs {18} /signer/ +use anchor_lang::prelude::*; + +declare_id!("BZLiJ62bzRryYp9mRobz47uA66WDgtfTXhhgM25tJyx5"); + +#[program] +mod hello_anchor { + use super::*; + pub fn test_instruction(ctx: Context) -> Result<()> { + msg!("PDA: {}", ctx.accounts.pda_account.key()); + Ok(()) + } +} + +#[derive(Accounts)] +pub struct InstructionAccounts<'info> { + pub signer: Signer<'info>, + #[account( + seeds = [b"hello_world", signer.key().as_ref()], + bump, + )] + pub pda_account: SystemAccount<'info>, +} +``` + + + + +IDL файл програми включає насіння PDA, визначені в обмеженні `seeds`. + +- Статичне насіння `b"hello_world"` перетворюється на байтові значення. +- Динамічне насіння включається як посилання на акаунт підписанта. + +```json {22-29} +{ + "address": "BZLiJ62bzRryYp9mRobz47uA66WDgtfTXhhgM25tJyx5", + "metadata": { + "name": "hello_anchor", + "version": "0.1.0", + "spec": "0.1.0", + "description": "Created with Anchor" + }, + "instructions": [ + { + "name": "test_instruction", + "discriminator": [33, 223, 61, 208, 32, 193, 201, 79], + "accounts": [ + { + "name": "signer", + "signer": true + }, + { + "name": "pda_account", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [104, 101, 108, 108, 111, 95, 119, 111, 114, 108, 100] + }, + { + "kind": "account", + "path": "signer" + } + ] + } + } + ], + "args": [] + } + ] +} +``` + + + + +Клієнт Anchor може автоматично визначити адресу PDA, використовуючи IDL файл. + +У наведеному нижче прикладі Anchor автоматично визначає адресу PDA, +використовуючи гаманець постачальника як підписанта, а його публічний ключ як +динамічне насіння для отримання PDA. Це усуває необхідність явного отримання PDA +під час побудови інструкції. + +```ts {13} +import * as anchor from "@coral-xyz/anchor"; +import { Program } from "@coral-xyz/anchor"; +import { HelloAnchor } from "../target/types/hello_anchor"; + +describe("hello_anchor", () => { + // Configure the client to use the local cluster. + anchor.setProvider(anchor.AnchorProvider.env()); + + const program = anchor.workspace.HelloAnchor as Program; + + it("Is initialized!", async () => { + // Add your test here. + const tx = await program.methods.testInstruction().rpc(); + console.log("Your transaction signature", tx); + }); +}); +``` + +Коли інструкція викликається, PDA виводиться в журнали програми, як це визначено +в інструкції програми. + +```{3} +Program BZLiJ62bzRryYp9mRobz47uA66WDgtfTXhhgM25tJyx5 invoke [1] +Program log: Instruction: TestInstruction +Program log: PDA: 3Hikt5mpKaSS4UNA5Du1TZJ8tp4o8VC8YWW6X9vtfVnJ +Program BZLiJ62bzRryYp9mRobz47uA66WDgtfTXhhgM25tJyx5 consumed 18505 of 200000 compute units +Program BZLiJ62bzRryYp9mRobz47uA66WDgtfTXhhgM25tJyx5 success +``` + + + diff --git a/docs/locales/uk/programs/anchor/program-structure.md b/docs/locales/uk/programs/anchor/program-structure.md new file mode 100644 index 000000000..e37a5eac7 --- /dev/null +++ b/docs/locales/uk/programs/anchor/program-structure.md @@ -0,0 +1,397 @@ +--- +title: Структура програми Anchor +description: + Дізнайтеся про структуру програм Anchor, включаючи основні макроси та їх роль + у спрощенні розробки програм для Solana +sidebarLabel: Структура програми +sidebarSortOrder: 1 +--- + +[Фреймворк Anchor](https://www.anchor-lang.com/) використовує +[макроси Rust](https://doc.rust-lang.org/book/ch19-06-macros.html) для зменшення +обсягу шаблонного коду та спрощення реалізації загальних перевірок безпеки, +необхідних для написання програм для Solana. + +Основні макроси, які використовуються в програмі Anchor, включають: + +- [`declare_id`](#declare-id-macro): Визначає on-chain адресу програми +- [`#[program]`](#program-macro): Визначає модуль, що містить логіку інструкцій + програми +- [`#[derive(Accounts)]`](#derive-accounts-macro): Застосовується до структур + для вказівки списку акаунтів, необхідних для інструкції +- [`#[account]`](#account-macro): Застосовується до структур для створення + користувацьких типів акаунтів для програми + +## Приклад програми + +Давайте розглянемо просту програму, яка демонструє використання вищезгаданих +макросів, щоб зрозуміти основну структуру програми Anchor. + +Наведена нижче програма створює новий акаунт (`NewAccount`), який зберігає +значення `u64`, передане в інструкцію `initialize`. + +```rust filename="lib.rs" +use anchor_lang::prelude::*; + +declare_id!("11111111111111111111111111111111"); + +#[program] +mod hello_anchor { + use super::*; + pub fn initialize(ctx: Context, data: u64) -> Result<()> { + ctx.accounts.new_account.data = data; + msg!("Changed data to: {}!", data); + Ok(()) + } +} + +#[derive(Accounts)] +pub struct Initialize<'info> { + #[account(init, payer = signer, space = 8 + 8)] + pub new_account: Account<'info, NewAccount>, + #[account(mut)] + pub signer: Signer<'info>, + pub system_program: Program<'info, System>, +} + +#[account] +pub struct NewAccount { + data: u64, +} +``` + +## Макрос `declare_id!` + +Макрос +[`declare_id`](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/attribute/account/src/lib.rs#L430) +вказує on-chain адресу програми, відому як ID програми. + +```rust filename="lib.rs" {3} +use anchor_lang::prelude::*; + +declare_id!("11111111111111111111111111111111"); +``` + +За замовчуванням, ID програми — це публічний ключ ключової пари, згенерованої за +адресою `/target/deploy/your_program_name.json`. + +Щоб оновити значення ID програми в макросі `declare_id` за допомогою публічного +ключа ключової пари з файлу `/target/deploy/your_program_name.json`, виконайте +наступну команду: + +```shell filename="Terminal" +anchor keys sync +``` + +Команда `anchor keys sync` корисна для виконання при клонуванні репозиторію, де +значення ID програми в макросі `declare_id` клонованого репозиторію не буде +співпадати з тим, що генерується при виконанні команди `anchor build` локально. + +## Макрос `#[program]` + +Макрос +[`#[program]`](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/attribute/program/src/lib.rs#L12) +визначає модуль, що містить усі обробники інструкцій для вашої програми. Кожна +публічна функція в межах цього модуля відповідає інструкції, яку можна +викликати. + +```rust filename="lib.rs" {5, 8-12} +use anchor_lang::prelude::*; + +declare_id!("11111111111111111111111111111111"); + +#[program] +mod hello_anchor { + use super::*; + pub fn initialize(ctx: Context, data: u64) -> Result<()> { + ctx.accounts.new_account.data = data; + msg!("Changed data to: {}!", data); + Ok(()) + } +} + +#[derive(Accounts)] +pub struct Initialize<'info> { + #[account(init, payer = signer, space = 8 + 8)] + pub new_account: Account<'info, NewAccount>, + #[account(mut)] + pub signer: Signer<'info>, + pub system_program: Program<'info, System>, +} + +#[account] +pub struct NewAccount { + data: u64, +} +``` + +### Контекст інструкції + +Обробники інструкцій — це функції, які визначають логіку, що виконується, коли +інструкція викликається. Перший параметр кожного обробника має тип `Context`, +де `T` — це структура, яка реалізує трейд `Accounts` і вказує на акаунти, які +потрібні для інструкції. + +Тип +[`Context`](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/src/context.rs#L24) +надає інструкції доступ до наступних неаргументних входів: + +```rust +pub struct Context<'a, 'b, 'c, 'info, T> { + /// Currently executing program id. + pub program_id: &'a Pubkey, + /// Deserialized accounts. + pub accounts: &'b mut T, + /// Remaining accounts given but not deserialized or validated. + /// Be very careful when using this directly. + pub remaining_accounts: &'c [AccountInfo<'info>], + /// Bump seeds found during constraint validation. This is provided as a + /// convenience so that handlers don't have to recalculate bump seeds or + /// pass them in as arguments. + pub bumps: BTreeMap, +} +``` + +Поля `Context` можна отримати в інструкції за допомогою позначення через крапку: + +- `ctx.accounts`: Акаунти, необхідні для інструкції +- `ctx.program_id`: Публічний ключ програми (адреса) +- `ctx.remaining_accounts`: Додаткові акаунти, які не вказані в структурі + `Accounts`. +- `ctx.bumps`: Bump seed для будь-яких акаунтів + [Program Derived Address (PDA)](/docs/core/pda.md), вказаних у структурі + `Accounts` + +Додаткові параметри є необов'язковими та можуть бути включені для вказівки +аргументів, які повинні бути надані при виклику інструкції. + +```rust filename="lib.rs" /Context/ /data/1 +pub fn initialize(ctx: Context, data: u64) -> Result<()> { + ctx.accounts.new_account.data = data; + msg!("Changed data to: {}!", data); + Ok(()) +} +``` + +У цьому прикладі структура `Initialize` реалізує трейд `Accounts`, де кожне поле +в структурі представляє акаунт, необхідний для інструкції `initialize`. + +```rust filename="lib.rs" /Initialize/ /Accounts/ +#[program] +mod hello_anchor { + use super::*; + pub fn initialize(ctx: Context, data: u64) -> Result<()> { + ctx.accounts.new_account.data = data; + msg!("Changed data to: {}!", data); + Ok(()) + } +} + +#[derive(Accounts)] +pub struct Initialize<'info> { + #[account(init, payer = signer, space = 8 + 8)] + pub new_account: Account<'info, NewAccount>, + #[account(mut)] + pub signer: Signer<'info>, + pub system_program: Program<'info, System>, +} +``` + +## Макрос `#[derive(Accounts)]` + +Макрос +[`#[derive(Accounts)]`](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/derive/accounts/src/lib.rs#L630) +застосовується до структури для вказівки акаунтів, які повинні бути надані під +час виклику інструкції. Цей макрос реалізує трейд +[`Accounts`](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/src/lib.rs#L105), +що спрощує перевірку акаунтів, а також серіалізацію та десеріалізацію даних +акаунтів. + +```rust /Accounts/ {1} +#[derive(Accounts)] +pub struct Initialize<'info> { + #[account(init, payer = signer, space = 8 + 8)] + pub new_account: Account<'info, NewAccount>, + #[account(mut)] + pub signer: Signer<'info>, + pub system_program: Program<'info, System>, +} +``` + +Кожне поле в структурі представляє акаунт, необхідний для інструкції. Іменування +кожного поля є довільним, але рекомендується використовувати описове ім'я, яке +вказує на призначення акаунту. + +```rust /signer/2 /new_account/ /system_program/ +#[derive(Accounts)] +pub struct Initialize<'info> { + #[account(init, payer = signer, space = 8 + 8)] + pub new_account: Account<'info, NewAccount>, + #[account(mut)] + pub signer: Signer<'info>, + pub system_program: Program<'info, System>, +} +``` + +### Перевірка акаунтів + +Для запобігання вразливостям безпеки важливо перевіряти, що акаунти, надані +інструкції, є очікуваними. Акаунти перевіряються в програмах Anchor двома +способами, які зазвичай використовуються разом: + +- [Обмеження акаунтів](https://www.anchor-lang.com/docs/account-constraints): + Обмеження визначають додаткові умови, які акаунт повинен задовольняти, щоб + вважатися дійсним для інструкції. Обмеження застосовуються за допомогою + атрибута `#[account(..)]`, який розміщується над полем у структурі, що + реалізує трейд `Accounts`. + + Реалізацію обмежень можна знайти + [тут](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/syn/src/parser/accounts/constraints.rs). + + ```rust {3, 5} + #[derive(Accounts)] + pub struct Initialize<'info> { + #[account(init, payer = signer, space = 8 + 8)] + pub new_account: Account<'info, NewAccount>, + #[account(mut)] + pub signer: Signer<'info>, + pub system_program: Program<'info, System>, + } + ``` + +- [Типи акаунтів](https://www.anchor-lang.com/docs/account-types): Anchor надає + різні типи акаунтів, щоб допомогти гарантувати, що акаунт, наданий клієнтом, + відповідає тому, що очікує програма. + + Реалізацію типів акаунтів можна знайти + [тут](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/src/accounts). + + ```rust /Account/2 /Signer/ /Program/ + #[derive(Accounts)] + pub struct Initialize<'info> { + #[account(init, payer = signer, space = 8 + 8)] + pub new_account: Account<'info, NewAccount>, + #[account(mut)] + pub signer: Signer<'info>, + pub system_program: Program<'info, System>, + } + ``` + +Коли інструкція в програмі Anchor викликається, програма спочатку перевіряє +надані акаунти перед виконанням логіки інструкції. Після перевірки ці акаунти +можна отримати в інструкції за допомогою синтаксису `ctx.accounts`. + +```rust filename="lib.rs" /ctx.accounts.new_account/ /new_account/ /Initialize/ +use anchor_lang::prelude::*; + +declare_id!("11111111111111111111111111111111"); + +#[program] +mod hello_anchor { + use super::*; + pub fn initialize(ctx: Context, data: u64) -> Result<()> { + ctx.accounts.new_account.data = data; + msg!("Changed data to: {}!", data); + Ok(()) + } +} + +#[derive(Accounts)] +pub struct Initialize<'info> { + #[account(init, payer = signer, space = 8 + 8)] + pub new_account: Account<'info, NewAccount>, + #[account(mut)] + pub signer: Signer<'info>, + pub system_program: Program<'info, System>, +} + +#[account] +pub struct NewAccount { + data: u64, +} +``` + +## Макрос `#[account]` + +Макрос +[`#[account]`](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/attribute/account/src/lib.rs#L66) +застосовується до структур, які визначають дані, що зберігаються в +користувацьких акаунтах, створених вашою програмою. + +```rust +#[account] +pub struct NewAccount { + data: u64, +} +``` + +Цей макрос реалізує різні трейди +[детальніше тут](https://docs.rs/anchor-lang/latest/anchor_lang/attr.account.html). +Основні функціональні можливості макроса `#[account]` включають: + +- [Призначення власника програми](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/attribute/account/src/lib.rs#L119-L132): + При створенні акаунту власник акаунту автоматично встановлюється на програму, + вказану в `declare_id`. +- [Встановлення дискримінатора](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/attribute/account/src/lib.rs#L101-L117): + Унікальний 8-байтовий дискримінатор, що визначає тип акаунту, додається як + перші 8 байтів даних акаунту під час його ініціалізації. Це допомагає + відрізняти типи акаунтів і використовується для перевірки акаунтів. +- [Серіалізація та десеріалізація даних](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/attribute/account/src/lib.rs#L202-L246): + Дані акаунту автоматично серіалізуються та десеріалізуються відповідно до типу + акаунту. + +```rust filename="lib.rs" /data/2,6 /NewAccount/ {24-27} +use anchor_lang::prelude::*; + +declare_id!("11111111111111111111111111111111"); + +#[program] +mod hello_anchor { + use super::*; + pub fn initialize(ctx: Context, data: u64) -> Result<()> { + ctx.accounts.new_account.data = data; + msg!("Changed data to: {}!", data); + Ok(()) + } +} + +#[derive(Accounts)] +pub struct Initialize<'info> { + #[account(init, payer = signer, space = 8 + 8)] + pub new_account: Account<'info, NewAccount>, + #[account(mut)] + pub signer: Signer<'info>, + pub system_program: Program<'info, System>, +} + +#[account] +pub struct NewAccount { + data: u64, +} +``` + +### Дискримінатор акаунту + +Дискримінатор акаунту в програмі Anchor — це 8-байтовий ідентифікатор, +унікальний для кожного типу акаунту. Він отримується з перших 8 байтів SHA256 +хешу рядка `account:`. Цей дискримінатор зберігається як перші 8 +байтів даних акаунту під час його створення. + +При створенні акаунту в програмі Anchor для дискримінатора повинно бути виділено +8 байтів. + +```rust /8/1 +#[account(init, payer = signer, space = 8 + 8)] +pub new_account: Account<'info, NewAccount>, +``` + +Дискримінатор використовується в наступних двох сценаріях: + +- Ініціалізація: Коли акаунт створюється, дискримінатор встановлюється як перші + 8 байтів даних акаунту. +- Десеріалізація: Коли дані акаунту десеріалізуються, перші 8 байтів даних + акаунту перевіряються на відповідність дискримінатору очікуваного типу + акаунту. + +Якщо є невідповідність, це вказує на те, що клієнт надав неочікуваний акаунт. +Цей механізм служить перевіркою валідності акаунтів у програмах Anchor. diff --git a/docs/locales/uk/programs/deploying.md b/docs/locales/uk/programs/deploying.md new file mode 100644 index 000000000..c4b2bd845 --- /dev/null +++ b/docs/locales/uk/programs/deploying.md @@ -0,0 +1,333 @@ +--- +title: "Розгортання програм" +description: + Розгортання програм на ланцюгу можна здійснити за допомогою Solana CLI, + використовуючи Upgradable BPF loader для завантаження скомпільованого + байт-коду на блокчейн Solana. +sidebarSortOrder: 2 +--- + +Програми Solana зберігаються в "виконуваних" акаунтах в мережі. Ці акаунти +містять скомпільований байт-код програми, який визначає інструкції, які +користувачі викликають для взаємодії з програмою. + +## Команди CLI + +Цей розділ призначений як довідник для базових команд CLI для створення та +розгортання програм Solana. Для покрокового посібника зі створення вашої першої +програми почніть з [Розробки програм на Rust](/docs/programs/rust). + +### Збірка програми + +Щоб побудувати вашу програму, використовуйте команду `cargo build-sbf`. + +```shell +cargo build-sbf +``` + +Ця команда: + +1. Скомпілює вашу програму +2. Створить директорію `target/deploy` +3. Згенерує файл `.so`, де `` відповідає імені вашої + програми у файлі `Cargo.toml` + +Вивантажений файл `.so` містить скомпільований байт-код вашої програми, який +буде збережено в акаунті Solana під час розгортання вашої програми. + +### Розгортання програми + +Щоб розгорнути вашу програму, використовуйте команду `solana program deploy`, +вказавши шлях до файлу `.so`, який був створений командою `cargo build-sbf`. + +```shell +solana program deploy ./target/deploy/your_program.so +``` + +Під час періодів завантаження є кілька додаткових прапорців, які можна +використовувати для полегшення розгортання програми. + +- `--with-compute-unit-price`: Встановіть ціну за обчислювальні одиниці для + транзакції, в increments 0.000001 лампортів (мікро-лампорти) за обчислювальну + одиницю. +- `--max-sign-attempts`: Максимальна кількість спроб підписати або повторно + підписати транзакції після закінчення терміну дії blockhash. Якщо будь-які + транзакції, надіслані під час розгортання програми, залишаються + непідтвердженими після закінчення терміну дії початково вибраного останнього + blockhash, ці транзакції будуть повторно підписані з новим blockhash і + відправлені знову. Використовуйте цей параметр для налаштування максимальної + кількості спроб підписання транзакцій. Кожен blockhash є дійсним близько 60 + секунд, що означає, що використання значення за замовчуванням 5 призведе до + надсилання транзакцій щонайменше 5 хвилин або до тих пір, поки всі транзакції + не будуть підтверджені, залежно від того, що відбудеться раніше. [за + замовчуванням: 5] +- `--use-rpc`: Надсилайте транзакції запису до налаштованого RPC замість TPU + валідатора. Цей прапорець вимагає RPC з урахуванням ставки. + +Ви можете використовувати ці прапорці окремо або поєднувати їх разом. Наприклад: + +```shell +solana program deploy ./target/deploy/your_program.so --with-compute-unit-price 10000 --max-sign-attempts 1000 --use-rpc +``` + +- Використовуйте + [Priority Fee API від Helius](https://docs.helius.dev/guides/priority-fee-api) + для отримання оцінки пріоритетної плати, яку потрібно встановити за допомогою + прапорця `--with-compute-unit-price`. + +- Отримайте + [RPC з урахуванням ставки](https://solana.com/developers/guides/advanced/stake-weighted-qos) + від [Helius](https://www.helius.dev/) або [Triton](https://triton.one/) для + використання з прапорцем `--use-rpc`. Прапорець `--use-rpc` повинен + використовуватись тільки з RPC з урахуванням ставки. + +Щоб оновити ваш за умовчанням RPC URL за допомогою власної точки доступу RPC, +використовуйте команду `solana config set`. + +```shell +solana config set --url +``` + +Ви можете переглянути список програм, які ви розгорнули, використовуючи +підкоманду `program show`: + +```shell +solana program show --programs +``` + +Example output: + +``` +Program Id | Slot | Authority | Balance +2w3sK6CW7Hy1Ljnz2uqPrQsg4KjNZxD4bDerXDkSX3Q1 | 133132 | 4kh6HxYZiAebF8HWLsUWod2EaQQ6iWHpHYCz8UcmFbM1 | 0.57821592 SOL +``` + +### Оновлення програми + +Авторизація на оновлення програми може змінювати існуючу програму Solana, +розгортаючи новий файл `.so` на той самий ID програми. + +Щоб оновити існуючу програму Solana: + +- Змініть вихідний код вашої програми +- Виконайте команду `cargo build-sbf`, щоб згенерувати оновлений файл `.so` +- Виконайте команду `solana program deploy ./target/deploy/your_program.so`, щоб + розгорнути оновлений файл `.so` + +Авторизацію на оновлення можна змінити за допомогою підкоманди +`set-upgrade-authority` наступним чином: + +```shell +solana program set-upgrade-authority --new-upgrade-authority +``` + +### Незмінна програма + +Програму можна зробити незмінною, видаливши її авторизацію на оновлення. Це +незворотна дія. + +```shell +solana program set-upgrade-authority --final +``` + +Ви можете вказати, що програма має бути незмінною при розгортанні, встановивши +прапорець `--final` під час розгортання програми. + +```shell +solana program deploy ./target/deploy/your_program.so --final +``` + +### Закрити програму + +Ви можете закрити свою програму Solana, щоб повернути SOL, виділені для акаунту. +Закриття програми є незворотним, тому це слід робити обережно. Щоб закрити +програму, використовуйте підкоманду `program close`. Наприклад: + +```shell filename="Terminal" +solana program close 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz +--bypass-warning +``` + +Example output: + +``` +Closed Program Id 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz, 0.1350588 SOL +reclaimed +``` + +Зверніть увагу, що після закриття програми її ID програми не можна буде +використовувати знову. Спроба розгорнути програму з раніше закритим ID програми +призведе до помилки. + +``` +Error: Program 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz has been closed, use +a new Program Id +``` + +Якщо вам потрібно повторно розгорнути програму після її закриття, ви повинні +згенерувати новий ID програми. Щоб згенерувати нову ключову пару для програми, +виконайте наступну команду: + +```shell filename="Terminal" +solana-keygen new -o ./target/deploy/your_program-keypair.json --force +``` + +Альтернативно, ви можете видалити існуючий файл ключової пари і знову виконати +команду `cargo build-sbf`, що згенерує новий файл ключової пари. + +### Акаунти буфера програми + +Розгортання програми вимагає кількох транзакцій через обмеження в 1232 байти для +транзакцій на Solana. Проміжним кроком процесу розгортання є запис байт-коду +програми в тимчасовий "акаунт буфера". + +Цей акаунт буфера автоматично закривається після успішного розгортання програми. +Однак, якщо розгортання не вдалося, акаунт буфера залишається, і ви можете: + +- Продовжити розгортання, використовуючи існуючий акаунт буфера +- Закрити акаунт буфера, щоб повернути виділений SOL (оренду) + +Ви можете перевірити, чи є відкриті акаунти буфера, використовуючи підкоманду +`program show`, наступним чином: + +```shell +solana program show --buffers +``` + +Example output: + +``` +Buffer Address | Authority | Balance +5TRm1DxYcXLbSEbbxWcQbEUCce7L4tVgaC6e2V4G82pM | 4kh6HxYZiAebF8HWLsUWod2EaQQ6iWHpHYCz8UcmFbM1 | 0.57821592 SOL +``` + +Ви можете продовжити до розгортання за допомогою підкоманди `program deploy` +наступним чином: + +```shell +solana program deploy --buffer 5TRm1DxYcXLbSEbbxWcQbEUCce7L4tVgaC6e2V4G82pM +``` + +Expected output on successful deployment: + +``` +Program Id: 2w3sK6CW7Hy1Ljnz2uqPrQsg4KjNZxD4bDerXDkSX3Q1 + +Signature: 3fsttJFskUmvbdL5F9y8g43rgNea5tYZeVXbimfx2Up5viJnYehWe3yx45rQJc8Kjkr6nY8D4DP4V2eiSPqvWRNL +``` + +To close buffer accounts, use the `program close` subcommand as follows: + +```shell +solana program close --buffers +``` + +### ELF Dump + +Внутрішні дані SBF shared object можна вивести в текстовий файл, щоб отримати +більше інформації про склад програми та те, що вона може виконувати під час +виконання. Вивантаження містить як ELF інформацію, так і список всіх символів та +інструкцій, що їх реалізують. Деякі з повідомлень журналу помилок BPF loader +будуть посилатися на конкретні номери інструкцій, де сталася помилка. Ці +посилання можна знайти у вивантаженні ELF, щоб ідентифікувати помилкову +інструкцію та її контекст. + +```shell +cargo build-bpf --dump +``` + +Файл буде виведено до `/target/deploy/your_program-dump.txt`. + +## Процес розгортання програми + +Розгортання програми на Solana вимагає кількох транзакцій через максимальний +ліміт розміру транзакцій у 1232 байти. Solana CLI надсилає ці транзакції за +допомогою підкоманди `solana program deploy`. Процес можна розділити на наступні +3 фази: + +1. [Ініціалізація буфера](https://github.com/solana-labs/solana/blob/7409d9d2687fba21078a745842c25df805cdf105/cli/src/program.rs#L2113): + Спочатку CLI надсилає транзакцію, яка + [створює акаунт буфера](https://github.com/solana-labs/solana/blob/7409d9d2687fba21078a745842c25df805cdf105/cli/src/program.rs#L1903) + достатнього розміру для байт-коду, що розгортається. Також викликається + [інструкція ініціалізації буфера](https://github.com/solana-labs/solana/blob/7409d9d2687fba21078a745842c25df805cdf105/programs/bpf_loader/src/lib.rs#L320), + щоб встановити право власності на буфер і обмежити записи на вибрану адресу + розробника. +2. [Запис буфера](https://github.com/solana-labs/solana/blob/7409d9d2687fba21078a745842c25df805cdf105/cli/src/program.rs#L2129): + Після ініціалізації акаунту буфера CLI + [розбиває байт-код програми](https://github.com/solana-labs/solana/blob/7409d9d2687fba21078a745842c25df805cdf105/cli/src/program.rs#L1940) + на шматки розміром близько 1 КБ і + [відправляє транзакції зі швидкістю 100 транзакцій за секунду](https://github.com/solana-labs/solana/blob/7409d9d2687fba21078a745842c25df805cdf105/client/src/tpu_client.rs#L133), + щоб записати кожен шматок за допомогою + [інструкції запису буфера](https://github.com/solana-labs/solana/blob/7409d9d2687fba21078a745842c25df805cdf105/programs/bpf_loader/src/lib.rs#L334). + Ці транзакції надсилаються безпосередньо до порту обробки транзакцій (TPU) + поточного лідера і обробляються паралельно. Після того, як всі транзакції + будуть надіслані, CLI + [опитує RPC API партіями підписів транзакцій](https://github.com/solana-labs/solana/blob/7409d9d2687fba21078a745842c25df805cdf105/client/src/tpu_client.rs#L216), + щоб переконатися, що кожен запис був успішним і підтвердженим. +3. [Фіналізація](https://github.com/solana-labs/solana/blob/7409d9d2687fba21078a745842c25df805cdf105/cli/src/program.rs#L1807): + Після завершення записів CLI + [надсилає фінальну транзакцію](https://github.com/solana-labs/solana/blob/7409d9d2687fba21078a745842c25df805cdf105/cli/src/program.rs#L2150) + для того, щоб + [розгорнути нову програму](https://github.com/solana-labs/solana/blob/7409d9d2687fba21078a745842c25df805cdf105/programs/bpf_loader/src/lib.rs#L362) + або + [оновити існуючу програму](https://github.com/solana-labs/solana/blob/7409d9d2687fba21078a745842c25df805cdf105/programs/bpf_loader/src/lib.rs#L513). + В будь-якому випадку байт-код, записаний в акаунт буфера, буде скопійовано в + акаунт даних програми і перевірено. + +## Оновлювана програма BPF Loader + +Програма BPF loader є програмою, яка "володіє" всіма виконуваними акаунтами на +Solana. Коли ви розгортаєте програму, власник акаунту програми встановлюється на +програму BPF loader. + +### Акаунти стану + +Оновлювана програма BPF loader підтримує три різні типи акаунтів стану: + +1. [Акаунт програми](https://github.com/solana-labs/solana/blob/master/sdk/program/src/bpf_loader_upgradeable.rs#L34): + Це основний акаунт програми на ланцюгу, і його адреса зазвичай називається + "ID програми". ID програми — це те, на що посилаються інструкції транзакцій + для виклику програми. Акаунти програми незмінні після розгортання, тому ви + можете вважати їх проксі-акаунтами для байт-коду та стану, що зберігаються в + інших акаунтах. +2. [Акаунт даних програми](https://github.com/solana-labs/solana/blob/7409d9d2687fba21078a745842c25df805cdf105/sdk/program/src/bpf_loader_upgradeable.rs#L39): + Цей акаунт зберігає виконуваний байт-код програми на ланцюгу. Коли програма + оновлюється, дані цього акаунту оновлюються новим байт-кодом. Крім байт-коду, + акаунти даних програми також відповідають за зберігання слоту, коли вони були + востаннє змінені, та адреси єдиного акаунту, авторизованого для зміни акаунту + (ця адреса може бути очищена, щоб зробити програму незмінною). +3. [Акаунти буфера](https://github.com/solana-labs/solana/blob/7409d9d2687fba21078a745842c25df805cdf105/sdk/program/src/bpf_loader_upgradeable.rs#L27): + Ці акаунти тимчасово зберігають байт-код під час активного розгортання + програми через серію транзакцій. Вони також зберігають адресу єдиного + акаунту, який авторизований для виконання записів. + +### Інструкції + +Акаунти стану, перераховані вище, можуть бути змінені лише за допомогою однієї з +наступних інструкцій, що підтримуються програмою Upgradeable BPF Loader: + +1. [Ініціалізація буфера](https://github.com/solana-labs/solana/blob/7409d9d2687fba21078a745842c25df805cdf105/sdk/program/src/loader_upgradeable_instruction.rs#L21): + Створює акаунт буфера і зберігає адресу авторизації, яка дозволена змінювати + буфер. +2. [Запис](https://github.com/solana-labs/solana/blob/7409d9d2687fba21078a745842c25df805cdf105/sdk/program/src/loader_upgradeable_instruction.rs#L28): + Записує байт-код на вказаний байтовий офсет в акаунті буфера. Записи + обробляються маленькими шматками через обмеження транзакцій Solana, + максимальний розмір яких складає 1232 байти. +3. [Розгортання](https://github.com/solana-labs/solana/blob/7409d9d2687fba21078a745842c25df805cdf105/sdk/program/src/loader_upgradeable_instruction.rs#L77): + Створює акаунт програми та акаунт даних програми. Він заповнює акаунт даних + програми, копіюючи байт-код, що зберігається в акаунті буфера. Якщо байт-код + є дійсним, акаунт програми буде встановлений як виконуваний, дозволяючи його + викликати. Якщо байт-код недійсний, інструкція не вдасться, і всі зміни + будуть скасовані. +4. [Оновлення](https://github.com/solana-labs/solana/blob/7409d9d2687fba21078a745842c25df805cdf105/sdk/program/src/loader_upgradeable_instruction.rs#L102): + Заповнює існуючий акаунт даних програми, копіюючи виконуваний байт-код з + акаунта буфера. Подібно до інструкції розгортання, вона буде успішною лише в + тому випадку, якщо байт-код є дійсним. +5. [Встановлення авторизації](https://github.com/solana-labs/solana/blob/7409d9d2687fba21078a745842c25df805cdf105/sdk/program/src/loader_upgradeable_instruction.rs#L114): + Оновлює авторизацію акаунта даних програми або акаунта буфера, якщо поточний + власник акаунту підписав транзакцію, що обробляється. Якщо авторизація буде + видалена без заміни, її можна буде встановити лише один раз і акаунт більше + не можна буде закрити. +6. [Закриття](https://github.com/solana-labs/solana/blob/7409d9d2687fba21078a745842c25df805cdf105/sdk/program/src/loader_upgradeable_instruction.rs#L127): + Очищає дані акаунта програми або акаунта буфера та повертає SOL, використані + для депозиту звільнення від оренди. diff --git a/docs/locales/uk/programs/examples.md b/docs/locales/uk/programs/examples.md new file mode 100644 index 000000000..e20f39553 --- /dev/null +++ b/docs/locales/uk/programs/examples.md @@ -0,0 +1,157 @@ +--- +title: "Приклади програм" +description: + "Список прикладів програм для Solana на різних мовах і фреймворках, які можуть + допомогти вам вивчити та використовувати їх як посилання для ваших власних + проектів." +tags: + - quickstart + - program + - anchor + - javascript + - native + - rust + - token22 + - token extensions +keywords: + - rust + - cargo + - toml + - program + - tutorial + - intro to solana development + - blockchain developer + - blockchain tutorial + - web3 developer + - anchor +sidebarSortOrder: 3 +--- + +Репозиторій +[Solana Program Examples](https://github.com/solana-developers/program-examples) +на GitHub пропонує кілька підпапок, кожна з яких містить приклади коду для +різних парадигм програмування Solana та мов, створених, щоб допомогти +розробникам вивчати та експериментувати з розробкою на блокчейні Solana. + +Ви можете знайти приклади в репозиторії `solana-developers/program-examples` +разом з файлами README, що пояснюють, як запускати різні приклади. Більшість +прикладів є самодостатніми та доступні на рідному Rust (тобто без використання +фреймворку) та [Anchor](https://www.anchor-lang.com/docs/installation). Також є +список прикладів, які ми з радістю б +[побачили як внески](https://github.com/solana-developers/program-examples?tab=readme-ov-file#examples-wed-love-to-see). + +У репозиторії ви знайдете наступну підпапку, кожну з яких з різними прикладами +програм: + +- [Основи](#basics) +- [Стиснення](#compression) +- [Оракули](#oracles) +- [Токени](#tokens) +- [Token 2022 (Розширення токенів)](#token-2022-token-extensions) +- [Перерва](#break) + - [Збірка та запуск](#build-and-run) + +## Основи + +Містить серію прикладів, які демонструють основні кроки для створення програм +Solana, використовуючи рідні бібліотеки Rust. Ці приклади призначені для того, +щоб допомогти розробникам зрозуміти основні концепції програмування Solana. + +| Назва прикладу | Опис | Мова | +| --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | ------------------------- | +| [Дані акаунта](https://github.com/solana-developers/program-examples/tree/main/basics/account-data) | Збереження адреси з ім'ям, номером будинку, вулицею та містом в акаунті. | Native, Anchor | +| [Перевірка акаунтів](https://github.com/solana-developers/program-examples/tree/main/basics/checking-accounts) | Уроки безпеки, що показують, як виконувати перевірки акаунтів | Native, Anchor | +| [Закриття акаунта](https://github.com/solana-developers/program-examples/tree/main/basics/close-account) | Показує, як закривати акаунти, щоб повернути оренду. | Native, Anchor | +| [Лічильник](https://github.com/solana-developers/program-examples/tree/main/basics/counter) | Простий програмний лічильник на всіх різних архітектурах. | Native, Anchor, mpl-stack | +| [Створення акаунта](https://github.com/solana-developers/program-examples/tree/main/basics/create-account) | Як створити системний акаунт в межах програми. | Native, Anchor | +| [Перехресний виклик програми](https://github.com/solana-developers/program-examples/tree/main/basics/cross-program-invocation) | Використовуючи аналогію з рукою та важелем, показує, як викликати іншу програму з програми. | Native, Anchor | +| [Hello Solana](https://github.com/solana-developers/program-examples/tree/main/basics/hello-solana) | Приклад "Hello world", який просто виводить hello world у журналах транзакцій. | Native, Anchor | +| [Pda Rent payer](https://github.com/solana-developers/program-examples/tree/main/basics/pda-rent-payer) | Показує, як можна використовувати лампорти з PDA для оплати нового акаунта. | Native, Anchor | +| [Обробка інструкцій](https://github.com/solana-developers/program-examples/tree/main/basics/processing-instructions) | Показує, як обробляти рядкові дані інструкцій та u32. | Native, Anchor | +| [Програма з похідними адресами](https://github.com/solana-developers/program-examples/tree/main/basics/program-derived-addresses) | Показує, як використовувати насіння для посилання на PDA та збереження даних в ньому. | Native, Anchor | +| [Перерозподіл](https://github.com/solana-developers/program-examples/tree/main/basics/realloc) | Показує, як збільшувати та зменшувати розмір існуючого акаунта. | Native, Anchor | +| [Оренда](https://github.com/solana-developers/program-examples/tree/main/basics/rent) | Тут ви дізнаєтесь, як обчислювати вимоги оренди в межах програми. | Native, Anchor | +| [Розташування репозиторію](https://github.com/solana-developers/program-examples/tree/main/basics/repository-layout) | Рекомендації щодо структурування вашого макету програми. | Native, Anchor | +| [Передача SOL](https://github.com/solana-developers/program-examples/tree/main/basics/transfer-sol) | Різні методи передачі SOL для системних акаунтів та PDA. | Native, Anchor, Seahorse | + +## Стиснення + +Містить серію прикладів, які демонструють, як використовувати +[стиснення стану](/docs/advanced/state-compression.md) на Solana. Головним чином +фокусується на стиснених NFT (cNFT). + +| Назва прикладу | Опис | Мова | +| ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ------ | +| [cNFT-burn](https://github.com/solana-developers/program-examples/tree/main/compression/cnft-burn) | Для знищення cNFT він може бути спалений. Цей приклад показує, як це зробити в програмі. | Anchor | +| [cNFT-Vault](https://github.com/solana-developers/program-examples/tree/main/compression/cnft-vault/anchor) | Як зберігати cNFT в програмі та відправляти його знову. | Anchor | +| [cutils](https://github.com/solana-developers/program-examples/tree/main/compression/cutils) | Набір утиліт для, наприклад, мінтування та перевірки cNFT в програмі. | Anchor | + +## Оракули + +Оракули дозволяють використовувати дані поза ланцюгом в програмах. + +| Назва прикладу | Опис | Мова | +| ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------- | ------ | +| [Pyth](https://github.com/solana-developers/program-examples/tree/main/oracles/pyth) | Pyth надає дані про ціни токенів для використання в програмах на ланцюгу. | Anchor | + +## Токени + +Більшість токенів на Solana використовують стандарт токенів Solana Program +Library (SPL). Тут ви знайдете багато прикладів, як створювати, передавати, +спалювати токени та навіть як взаємодіяти з ними в програмах. + +| Назва прикладу | Опис | Мова | +| --------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | -------------- | +| [Створення токена](https://github.com/solana-developers/program-examples/tree/main/tokens/create-token) | Як створити токен та додати метадані метаплекса до нього. | Anchor, Native | +| [NFT Minter](https://github.com/solana-developers/program-examples/tree/main/tokens/nft-minter) | Мінтування тільки однієї кількості токену, а потім видалення права на мінтинг. | Anchor, Native | +| [PDA Mint Authority](https://github.com/solana-developers/program-examples/tree/main/tokens/pda-mint-authority) | Показує, як змінити право на мінтинг токенів через PDA. | Anchor, Native | +| [SPL Token Minter](https://github.com/solana-developers/program-examples/tree/main/tokens/spl-token-minter) | Пояснює, як використовувати Associated Token Accounts для відслідковування токен акаунтів. | Anchor, Native | +| [Token Swap](https://github.com/solana-developers/program-examples/tree/main/tokens/token-swap) | Розширений приклад, який показує, як побудувати AMM (автоматизований маркет-мейкер) пул для SPL токенів. | Anchor | +| [Передача токенів](https://github.com/solana-developers/program-examples/tree/main/tokens/transfer-tokens) | Показує, як передавати SPL токени за допомогою CPIs у програму токенів. | Anchor, Native | +| [Token-2022](https://github.com/solana-developers/program-examples/tree/main/tokens/token-2022) | Див. Token 2022 (Розширення токенів). | Anchor, Native | + +## Token 2022 (Розширення токенів) + +Token 2022 — це новий стандарт для токенів на Solana. Це більш гнучкий стандарт, +який дозволяє додавати до токену 16 різних розширень для додавання більшої +функціональності. + +| Назва прикладу | Опис | Мова | +| ------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- | ------ | +| [Основи](https://github.com/solana-developers/program-examples/tree/main/tokens/token-2022/basics/anchor) | Як створити токен, мінтувати та передавати його. | Anchor | +| [Стандартний стан акаунта](https://github.com/solana-developers/program-examples/tree/main/tokens/token-2022/default-account-state/native) | Це розширення дозволяє створювати акаунти токенів з певним станом, наприклад замороженими. | Native | +| [Право закриття мінта](https://github.com/solana-developers/program-examples/tree/main/tokens/token-2022/mint-close-authority) | З старою програмою токенів не було можливості закривати мінт. Тепер це можливо. | Native | +| [Багато розширень](https://github.com/solana-developers/program-examples/tree/main/tokens/token-2022/multiple-extensions) | Показує, як додавати кілька розширень до одного мінта | Native | +| [Вказівник метаданих NFT](https://github.com/solana-developers/program-examples/tree/main/tokens/token-2022/nft-meta-data-pointer) | Можна використовувати розширення метаданих для створення NFT та додавання динамічних метаданих на ланцюг. | Anchor | +| [Не передаваємий](https://github.com/solana-developers/program-examples/tree/main/tokens/token-2022/non-transferable/native) | Корисно, наприклад, для досягнень, програм рефералів або будь-яких токенів, які не можна передавати. | Native | +| [Плата за передачу](https://github.com/solana-developers/program-examples/tree/main/tokens/token-2022/transfer-fees) | Кожна передача токенів утримує певну кількість токенів у акаунті токена, яку потім можна забрати. | Native | +| [Transfer Hook](https://github.com/solana-developers/program-examples/tree/main/tokens/token-2022/transfer-hook) | Чотири приклади для додавання додаткової функціональності до вашого токена за допомогою CPI з програми токенів. | Anchor | + +## Break + +[Break](https://break.solana.com/) — це додаток на React, який дає користувачам +можливість відчути, наскільки швидко і ефективно працює мережа Solana. Чи +зможете ви _зламати_ блокчейн Solana? Протягом 15 секунд кожне натискання кнопки +або клавіші відправляє нову транзакцію в кластер. Ударте по клавіатурі так +швидко, як можете, і дивіться, як ваші транзакції підтверджуються в реальному +часі, поки мережа справляється з усім! + +Break можна грати на наших мережах Devnet, Testnet та Mainnet Beta. Ігри +безкоштовні на Devnet і Testnet, де сесія фінансується мережевим фонтаном. На +Mainnet Beta користувачі платять 0,08 SOL за гру. Сесійний акаунт можна +фінансувати через локальний гаманець keystore або скануючи QR-код з Trust Wallet +для переміщення токенів. + +[Клацніть тут, щоб зіграти в Break](https://break.solana.com/) + +### Збірка та запуск + +Спочатку отримайте останню версію прикладів коду: + +```shell +git clone https://github.com/solana-labs/break.git +cd break +``` + +Дотримуйтесь кроків у файлі +[README](https://github.com/solana-labs/break/blob/main/README.md) репозиторію. diff --git a/docs/locales/uk/programs/faq.md b/docs/locales/uk/programs/faq.md new file mode 100644 index 000000000..7514d785e --- /dev/null +++ b/docs/locales/uk/programs/faq.md @@ -0,0 +1,199 @@ +--- +title: "Часто задавані питання" +sidebarSortOrder: 7 +--- + +Публікуйте свої питання на +[StackExchange](https://solana.stackexchange.com/questions/ask). + +## Berkeley Packet Filter (BPF) + +Програми Solana на ланцюзі компілюються через +[інфраструктуру компілятора LLVM](https://llvm.org/) в +[Executable and Linkable Format (ELF)](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format), +яка містить варіацію +[Berkeley Packet Filter (BPF)](https://en.wikipedia.org/wiki/Berkeley_Packet_Filter) +байткоду. + +Оскільки Solana використовує інфраструктуру компілятора LLVM, програму можна +написати на будь-якій мові програмування, яка підтримує компіляцію в BPF бекенд +LLVM. + +BPF надає ефективний +[набір інструкцій](https://github.com/iovisor/bpf-docs/blob/master/eBPF.md), +який можна виконувати в інтерпретованій віртуальній машині або як ефективно +згенеровані нативні інструкції за допомогою just-in-time компіляції. + +## Карта пам'яті + +Віртуальна адресна карта пам'яті, яку використовують програми Solana SBF, є +фіксованою та має наступне розташування: + +- Код програми починається з адреси 0x100000000 +- Дані стека починаються з адреси 0x200000000 +- Дані купи починаються з адреси 0x300000000 +- Вхідні параметри програми починаються з адреси 0x400000000 + +Вищезазначені віртуальні адреси є початковими адресами, але програми отримують +доступ до підмножини карти пам'яті. Програма викликає паніку, якщо вона +намагається читати або записувати в віртуальну адресу, до якої не було надано +доступу, і повертається помилка `AccessViolation`, яка містить адресу та розмір +спроби порушення. + +## InvalidAccountData + +Ця помилка програми може статися з багатьох причин. Зазвичай це викликано +передачею акаунта в програму, якого програма не очікує, або через неправильне +положення акаунта в інструкції або акаунт, який не сумісний з виконуваною +інструкцією. + +Реалізація програми може також спричинити цю помилку при виконанні перехресної +інструкції між програмами, якщо забули надати акаунт для програми, яку ви +викликаєте. + +## InvalidInstructionData + +Ця помилка програми може статися при спробі десеріалізувати інструкцію, +перевірте, чи структура, передана в інструкцію, точно відповідає вимогам +програми. Між полями може бути деяке додаткове заповнення. Якщо програма +реалізує трейти Rust `Pack`, спробуйте упакувати і розпакувати тип інструкції +`T`, щоб визначити точне кодування, яке програма очікує. + +## MissingRequiredSignature + +Деякі інструкції вимагають, щоб акаунт був підписантом; ця помилка повертається, +якщо очікується підпис акаунта, але він відсутній. + +Реалізація програми може також викликати цю помилку при виконанні +[перехресного виклику програми](/docs/core/cpi.md), який вимагає підписаного +адреси програми, але передані насіння підписувача до `invoke_signed` не +збігаються з насіннями підписувача, що використовуються для створення адреси +програми [`create_program_address`](/docs/core/pda.md#createprogramaddress). + +## Стек + +SBF використовує стекові кадри замість змінного покажчика стеку. Кожен стековий +кадр має розмір 4 КБ. + +Якщо програма порушує розмір цього стекового кадру, компілятор повідомить про +перевищення розміру як попередження. + +Наприклад: + +```text +Error: Function _ZN16curve25519_dalek7edwards21EdwardsBasepointTable6create17h178b3d2411f7f082E Stack offset of -30728 exceeded max offset of -4096 by 26632 bytes, please minimize large stack variables +``` + +Повідомлення вказує, який символ перевищує розмір свого стекового кадру, але +ім'я може бути змінене. + +> Щоб деманглювати символ Rust, використовуйте +> [rustfilt](https://github.com/luser/rustfilt). + +Вищезазначене попередження походить від програми на Rust, тому демангльоване +ім'я символу: + +```shell +rustfilt _ZN16curve25519_dalek7edwards21EdwardsBasepointTable6create17h178b3d2411f7f082E +curve25519_dalek::edwards::EdwardsBasepointTable::create +``` + +Причина того, що виводиться попередження, а не помилка, полягає в тому, що деякі +залежні пакети можуть містити функціональність, яка порушує обмеження розміру +стекового кадру, навіть якщо програма не використовує цю функціональність. Якщо +програма порушить розмір стеку під час виконання, то буде виведено помилку +`AccessViolation`. + +Стекові кадри SBF займають діапазон віртуальних адрес, починаючи з +`0x200000000`. + +## Розмір купи + +Програми мають доступ до купи часу виконання через API Rust `alloc`. Для +швидкого виділення пам'яті використовується проста купа на 32 КБ. Куча не +підтримує `free` або `realloc`. + +Програми мають доступ до пам'яті об'ємом 32 КБ, починаючи з віртуальної адреси +0x300000000, і можуть реалізувати власну купу на основі специфічних потреб +програми. + +Програми на Rust реалізують купу безпосередньо, визначаючи власний +[`global_allocator`](https://github.com/solana-labs/solana/blob/d9b0fc0e3eec67dfe4a97d9298b15969b2804fab/sdk/program/src/entrypoint.rs#L72) + +## Завантажувачі + +Програми розгортаються і виконуються через завантажувачі часу виконання, наразі +підтримуються два завантажувачі: + +- [BPF Loader](https://github.com/solana-labs/solana/blob/7ddf10e602d2ed87a9e3737aa8c32f1db9f909d8/sdk/program/src/bpf_loader.rs#L17) +- [BPF loader (deprecated)](https://github.com/solana-labs/solana/blob/7ddf10e602d2ed87a9e3737aa8c32f1db9f909d8/sdk/program/src/bpf_loader_deprecated.rs#L14) + +Завантажувачі можуть підтримувати різні інтерфейси бінарних додатків, тому +розробники повинні пишуть свої програми для одного завантажувача і розгортають +їх на тому ж завантажувачі. Якщо програма, написана для одного завантажувача, +буде розгорнута на іншому, це зазвичай призведе до помилки `AccessViolation` +через невідповідність десеріалізації вхідних параметрів програми. + +Для практичних цілей програми завжди повинні бути написані для останнього BPF +завантажувача, і останній завантажувач є за умовчанням для інтерфейсу командного +рядка та JavaScript API. + +- [Точки входу програми Rust](/docs/programs/lang-rust.md#program-entrypoint) + +### Розгортання + +Розгортання програми SBF — це процес завантаження спільного об'єкта BPF в дані +акаунта програми та позначення акаунта як виконуваного. Клієнт розбиває спільний +об'єкт SBF на менші частини і надсилає їх як дані інструкцій +[`Write`](https://github.com/solana-labs/solana/blob/bc7133d7526a041d1aaee807b80922baa89b6f90/sdk/program/src/loader_instruction.rs#L13) +до завантажувача, де завантажувач записує ці дані в акаунт програми. Якщо всі +частини отримані, клієнт надсилає +[`Finalize`](https://github.com/solana-labs/solana/blob/bc7133d7526a041d1aaee807b80922baa89b6f90/sdk/program/src/loader_instruction.rs#L30) +інструкцію до завантажувача, завантажувач потім перевіряє, чи є дані SBF +дійсними і позначає акаунт програми як _виконуваний_. Після того, як акаунт +програми буде позначено як виконуваний, подальші транзакції можуть видавати +інструкції для цієї програми для обробки. + +Коли інструкція спрямована до виконуваної програми SBF, завантажувач конфігурує +середовище виконання програми, серіалізує вхідні параметри програми, викликає +точку входу програми і повідомляє про будь-які помилки. + +Додаткову інформацію див. в розділі +[розгортання програм](/docs/programs/deploying.md). + +### Серіалізація вхідних параметрів + +Завантажувачі SBF серіалізують вхідні параметри програми в масив байтів, який +потім передається в точку входу програми, де програма відповідає за їх +десеріалізацію на ланцюгу. Одна з змін між депрецованим завантажувачем і +поточним полягає в тому, що вхідні параметри серіалізуються так, що різні +параметри потрапляють на вирівняні офсети в межах вирівняного байтового масиву. +Це дозволяє реалізаціям десеріалізації безпосередньо посилатися на байтовий +масив і надавати вирівняні вказівники до програми. + +- [Десеріалізація параметрів програми на Rust](/docs/programs/lang-rust.md#parameter-deserialization) + +Останній завантажувач серіалізує вхідні параметри програми наступним чином (усе +кодування little endian): + +- 8 байт беззнакового числа акаунтів +- Для кожного акаунта: + - 1 байт, що вказує, чи є цей акаунт дублікатом, якщо ні — значення 0xff, в + іншому випадку значення — це індекс акаунта, з яким він є дублікатом. + - Якщо дублікати: 7 байт заповнювальної пам'яті + - Якщо не дублікати: + - 1 байт булевого типу, true, якщо акаунт є підписантом + - 1 байт булевого типу, true, якщо акаунт можна змінювати + - 1 байт булевого типу, true, якщо акаунт є виконуваним + - 4 байти заповнювальної пам'яті + - 32 байти публічного ключа акаунта + - 32 байти публічного ключа власника акаунта + - 8 байт беззнакового числа лампортів, які належать акаунту + - 8 байт беззнакового числа байтів даних акаунта + - x байт даних акаунта + - 10к байт заповнювальної пам'яті, використовується для realloc + - достатньо заповнювальної пам'яті для вирівнювання офсету до 8 байт + - 8 байт епохи оренди +- 8 байт беззнакового числа даних інструкцій +- x байт даних інструкцій +- 32 байти ID програми diff --git a/docs/locales/uk/programs/index.md b/docs/locales/uk/programs/index.md new file mode 100644 index 000000000..4189752bd --- /dev/null +++ b/docs/locales/uk/programs/index.md @@ -0,0 +1,5 @@ +--- +title: Developing Programs +sidebarSortOrder: 2 +metaOnly: true +--- diff --git a/docs/locales/uk/programs/limitations.md b/docs/locales/uk/programs/limitations.md new file mode 100644 index 000000000..955549850 --- /dev/null +++ b/docs/locales/uk/programs/limitations.md @@ -0,0 +1,109 @@ +--- +title: "Обмеження" +sidebarSortOrder: 6 +--- + +Розробка програм на блокчейні Solana має деякі вроджені обмеження. Нижче +наведено список поширених обмежень, з якими ви можете зіткнутися. + +## Бібліотеки Rust + +Оскільки програми Rust на блокчейні повинні бути детермінованими і виконуватись +у середовищі з обмеженими ресурсами та одночасною обробкою, вони мають деякі +обмеження щодо використання бібліотек. + +Програми Rust на блокчейні підтримують більшість бібліотек Rust, таких як +libstd, libcore, liballoc, а також багато сторонніх бібліотек. + +Проте існують певні обмеження через обмежені ресурси середовища та необхідність +детермінованості: + +- Немає доступу до: + - `rand` + - `std::fs` + - `std::net` + - `std::future` + - `std::process` + - `std::sync` + - `std::task` + - `std::thread` + - `std::time` +- Обмежений доступ до: + - `std::hash` + - `std::os` +- Використання Bincode є дуже ресурсомістким і його слід уникати. +- Форматування рядків також є ресурсомістким і повинно бути мінімізоване. +- Відсутня підтримка для `println!` та `print!`, замість цього використовуйте + макрос + [`msg!`](https://github.com/solana-labs/solana/blob/d9b0fc0e3eec67dfe4a97d9298b15969b2804fab/sdk/program/src/log.rs#L33). +- Під час виконання встановлено обмеження на кількість інструкцій, які програма + може виконати під час обробки однієї інструкції. Дивіться + [бюджет обчислень](/docs/core/fees.md#compute-budget) для більш детальної + інформації. + +## Бюджет обчислень + +Для запобігання зловживанню обчислювальними ресурсами блокчейну кожна транзакція +отримує [бюджет обчислень](/docs/terminology.md#compute-budget). Перевищення +цього бюджету призведе до провалу транзакції. + +Дивіться документацію про +[обмеження обчислень](/docs/core/fees.md#compute-budget) для більш детальної +інформації. + +## Глибина стеку викликів — помилка `CallDepthExceeded` + +Програми Solana мають обмежену глибину стеку викликів до **64 кадрів**. + +Якщо програма перевищує дозволену глибину стеку викликів, вона отримує помилку +`CallDepthExceeded`. + +## Глибина викликів CPI — помилка `CallDepth` + +Перехресні виклики між програмами дозволяють програмам викликати інші програми +безпосередньо, але наразі глибина обмежена до `4`. + +Якщо програма перевищує дозволену +[глибину викликів між програмами](/docs/core/cpi.md), вона отримує помилку +`CallDepth`. + +## Підтримка типів float у Rust + +Програми підтримують обмежений набір операцій із типами float у Rust. Якщо +програма намагається використовувати операцію із float, яка не підтримується, +виконання викликає помилку про нерозв’язаний символ. + +Операції із float виконуються через програмні бібліотеки (LLVM's float +built-ins) і споживають більше обчислювальних одиниць, ніж операції з цілими +числами. Загалом рекомендується використовувати фіксовану точку там, де це +можливо. + +[Математичні тести Solana Program Library](https://github.com/solana-labs/solana-program-library/tree/master/libraries/math) +демонструють продуктивність деяких математичних операцій. Для запуску тесту +синхронізуйте репозиторій і виконайте: + +```shell +cargo test-sbf -- --nocapture --test-threads=1 +``` + +Недавні результати показують, що операції із float споживають більше інструкцій +порівняно з еквівалентами для цілих чисел. Реалізації з фіксованою точкою також +будуть менш ресурсомісткими, ніж float: + +```text + u64 f32 +Multiply 8 176 +Divide 9 219 +``` + +## Статичні змінні, які можна змінювати + +Спільні об’єкти програм не підтримують змінювані спільні дані. Програми спільно +використовують один і той самий код та дані лише для читання, що означає, що +розробники не повинні включати статичні змінювані або глобальні змінні в +програми. У майбутньому може бути додано механізм копіювання при записі для +підтримки змінюваних даних. + +## Ділення зі знаком + +Набір інструкцій SBF не підтримує ділення зі знаком. diff --git a/docs/locales/uk/programs/rust/index.md b/docs/locales/uk/programs/rust/index.md new file mode 100644 index 000000000..16c3c79c3 --- /dev/null +++ b/docs/locales/uk/programs/rust/index.md @@ -0,0 +1,478 @@ +--- +title: Розробка програм на Rust +description: + Дізнайтеся, як розробляти програми для Solana, використовуючи Rust, включаючи + покрокові інструкції для створення, збірки, тестування та розгортання + смарт-контрактів на блокчейні Solana. +sidebarLabel: Програми на Rust +sidebarSortOrder: 1 +altRoutes: + - /docs/programs/lang-rust +--- + +Програми для Solana в основному розробляються за допомогою мови програмування +Rust. Ця сторінка зосереджена на написанні програм для Solana на Rust без +використання фреймворку Anchor, метод, який часто називають написанням "рідних +програм на Rust". + +Розробка рідних програм на Rust дає розробникам повний контроль над їхніми +програмами для Solana. Однак цей підхід вимагає більше ручної налаштування та +шаблонного коду порівняно з використанням фреймворку Anchor. Цей метод +рекомендований для розробників, які: + +- Шукають детальний контроль над логікою програми та оптимізаціями +- Хочуть зрозуміти основні концепції, перш ніж переходити до фреймворків вищого + рівня + +Для початківців ми рекомендуємо почати з фреймворку Anchor. Для отримання +додаткової інформації див. розділ [Anchor](/docs/programs/anchor). + +## Попередні вимоги + +Для детальних інструкцій по установці відвідайте сторінку +[встановлення](/docs/intro/installation). + +Перед тим, як почати, переконайтесь, що у вас встановлено наступне: + +- Rust: Мова програмування для створення програм для Solana. +- Solana CLI: Інструмент командного рядка для розробки на Solana. + +## Початок роботи + +Наведений приклад охоплює основні кроки для створення вашої першої програми для +Solana, написаної на Rust. Ми створимо мінімальну програму, яка виводить "Hello, +world!" в журнали програми. + + + +### Створення нової програми + +Спочатку створіть новий проект на Rust, використовуючи стандартну команду +`cargo init` з прапорцем `--lib`. + +```shell filename="Terminal" +cargo init hello_world --lib +``` + +Перейдіть до директорії проекту. Ви повинні побачити стандартні файли +`src/lib.rs` та `Cargo.toml`. + +```shell filename="Terminal" +cd hello_world +``` + +Далі додайте залежність `solana-program`. Це мінімальна залежність, необхідна +для побудови програми Solana. + +```shell filename="Terminal" +cargo add solana-program@1.18.26 +``` + +Далі додайте наступний фрагмент до файлу `Cargo.toml`. Якщо ви не включите цю +конфігурацію, директорія `target/deploy` не буде згенерована під час збірки +програми. + +```toml filename="Cargo.toml" +[lib] +crate-type = ["cdylib", "lib"] +``` + +Ваш файл `Cargo.toml` повинен виглядати наступним чином: + +```toml filename="Cargo.toml" +[package] +name = "hello_world" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] + +[dependencies] +solana-program = "1.18.26" +``` + +Далі замініть вміст файлу `src/lib.rs` на наступний код. Це мінімальна програма +для Solana, яка виводить "Hello, world!" в журнал програми, коли програма +викликається. + +Макрос `msg!` використовується в програмах Solana для виведення повідомлення в +журнал програми. + +```rs filename="lib.rs" +use solana_program::{ + account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, msg, pubkey::Pubkey, +}; + +entrypoint!(process_instruction); + +pub fn process_instruction( + _program_id: &Pubkey, + _accounts: &[AccountInfo], + _instruction_data: &[u8], +) -> ProgramResult { + msg!("Hello, world!"); + Ok(()) +} +``` + +### Збірка програми + +Далі побудуйте програму за допомогою команди `cargo build-sbf`. + +```shell filename="Terminal" +cargo build-sbf +``` + +Ця команда генерує директорію `target/deploy`, що містить два важливі файли: + +1. Файл `.so` (наприклад, `hello_world.so`): Це зкомпільована програма Solana, + яка буде розгорнута в мережі як "смарт-контракт". +2. Файл ключової пари (наприклад, `hello_world-keypair.json`): Публічний ключ + цієї ключової пари використовується як ID програми при розгортанні програми. + +Щоб переглянути ID програми, виконайте наступну команду у вашому терміналі. Ця +команда виводить публічний ключ ключової пари за вказаним шляхом до файлу: + +```shell filename="Terminal" +solana address -k ./target/deploy/hello_world-keypair.json +``` + +Example output: + +``` +4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz +``` + +### Тестування програми + +Далі протестуйте програму за допомогою crate `solana-program-test`. Додайте +наступні залежності до файлу `Cargo.toml`. + +```shell filename="Terminal" +cargo add solana-program-test@1.18.26 --dev +cargo add solana-sdk@1.18.26 --dev +cargo add tokio --dev +``` + +Додайте наступний тест до файлу `src/lib.rs`, під кодом програми. Це тестовий +модуль, який викликає програму hello world. + +```rs filename="lib.rs" +#[cfg(test)] +mod test { + use super::*; + use solana_program_test::*; + use solana_sdk::{signature::Signer, transaction::Transaction}; + + #[tokio::test] + async fn test_hello_world() { + let program_id = Pubkey::new_unique(); + let (mut banks_client, payer, recent_blockhash) = + ProgramTest::new("hello_world", program_id, processor!(process_instruction)) + .start() + .await; + + // Create the instruction to invoke the program + let instruction = + solana_program::instruction::Instruction::new_with_borsh(program_id, &(), vec![]); + + // Add the instruction to a new transaction + let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey())); + transaction.sign(&[&payer], recent_blockhash); + + // Process the transaction + let transaction_result = banks_client.process_transaction(transaction).await; + assert!(transaction_result.is_ok()); + } +} +``` + +Запустіть тест за допомогою команди `cargo test-sbf`. У журналі програми буде +виведено "Hello, world!". + +```shell filename="Terminal" +cargo test-sbf +``` + +Example output: + +```shell filename="Terminal" {4} /Program log: Hello, world!/ +running 1 test +[2024-10-18T21:24:54.889570000Z INFO solana_program_test] "hello_world" SBF program from /hello_world/target/deploy/hello_world.so, modified 35 seconds, 828 ms, 268 µs and 398 ns ago +[2024-10-18T21:24:54.974294000Z DEBUG solana_runtime::message_processor::stable_log] Program 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM invoke [1] +[2024-10-18T21:24:54.974814000Z DEBUG solana_runtime::message_processor::stable_log] Program log: Hello, world! +[2024-10-18T21:24:54.976848000Z DEBUG solana_runtime::message_processor::stable_log] Program 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM consumed 140 of 200000 compute units +[2024-10-18T21:24:54.976868000Z DEBUG solana_runtime::message_processor::stable_log] Program 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM success +test test::test_hello_world ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.13s +``` + +### Розгортання програми + +Далі розгорніть програму. Під час локальної розробки ми можемо використовувати +`solana-test-validator`. + +Спочатку налаштуйте Solana CLI для використання локального кластера Solana. + +```shell filename="Terminal" +solana config set -ul +``` + +Example output: + +``` +Config File: /.config/solana/cli/config.yml +RPC URL: http://localhost:8899 +WebSocket URL: ws://localhost:8900/ (computed) +Keypair Path: /.config/solana/id.json +Commitment: confirmed +``` + +Відкрийте новий термінал і виконайте команду `solana-test-validator`, щоб +запустити локальний валідатор. + +```shell filename="Terminal" +solana-test-validator +``` + +Поки тестовий валідатор працює, виконайте команду `solana program deploy` в +окремому терміналі, щоб розгорнути програму на локальному валідаторі. + +```shell filename="Terminal" +solana program deploy ./target/deploy/hello_world.so +``` + +Example output: + +``` +Program Id: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz +Signature: +5osMiNMiDZGM7L1e2tPHxU8wdB8gwG8fDnXLg5G7SbhwFz4dHshYgAijk4wSQL5cXiu8z1MMou5kLadAQuHp7ybH +``` + +Ви можете перевірити ID програми та підпис транзакції на +[Solana Explorer](https://explorer.solana.com/?cluster=custom&customUrl=http%3A%2F%2Flocalhost%3A8899). +Зверніть увагу, що кластер на Solana Explorer також повинен бути localhost. +Опція "Custom RPC URL" на Solana Explorer за замовчуванням встановлюється на +`http://localhost:8899`. + +### Виклик програми + +Далі ми продемонструємо, як викликати програму, використовуючи Rust клієнт. + +Спочатку створіть директорію `examples` та файл `client.rs`. + +```shell filename="Terminal" +mkdir -p examples +touch examples/client.rs +``` + +Додати натсупне до `Cargo.toml`. + +```toml filename="Cargo.toml" +[[example]] +name = "client" +path = "examples/client.rs" +``` + +Додати `solana-client` залежність. + +```shell filename="Terminal" +cargo add solana-client@1.18.26 --dev +``` + +Додайте наступний код до файлу `examples/client.rs`. Це Rust клієнтський скрипт, +який фінансує нову ключову пару для оплати зборів за транзакцію і потім викликає +програму hello world. + +```rs filename="example/client.rs" +use solana_client::rpc_client::RpcClient; +use solana_sdk::{ + commitment_config::CommitmentConfig, + instruction::Instruction, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, +}; +use std::str::FromStr; + +#[tokio::main] +async fn main() { + // Program ID (replace with your actual program ID) + let program_id = Pubkey::from_str("4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz").unwrap(); + + // Connect to the Solana devnet + let rpc_url = String::from("http://127.0.0.1:8899"); + let client = RpcClient::new_with_commitment(rpc_url, CommitmentConfig::confirmed()); + + // Generate a new keypair for the payer + let payer = Keypair::new(); + + // Request airdrop + let airdrop_amount = 1_000_000_000; // 1 SOL + let signature = client + .request_airdrop(&payer.pubkey(), airdrop_amount) + .expect("Failed to request airdrop"); + + // Wait for airdrop confirmation + loop { + let confirmed = client.confirm_transaction(&signature).unwrap(); + if confirmed { + break; + } + } + + // Create the instruction + let instruction = Instruction::new_with_borsh( + program_id, + &(), // Empty instruction data + vec![], // No accounts needed + ); + + // Add the instruction to new transaction + let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey())); + transaction.sign(&[&payer], client.get_latest_blockhash().unwrap()); + + // Send and confirm the transaction + match client.send_and_confirm_transaction(&transaction) { + Ok(signature) => println!("Transaction Signature: {}", signature), + Err(err) => eprintln!("Error sending transaction: {}", err), + } +} +``` + +Перед виконанням скрипту замініть ID програми в наведеному коді на той, що +відповідає вашій програмі. + +Ви можете отримати свій ID програми, виконавши наступну команду. + +```shell filename="Terminal" +solana address -k ./target/deploy/hello_world-keypair.json +``` + +```diff +#[tokio::main] +async fn main() { +- let program_id = Pubkey::from_str("4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz").unwrap(); ++ let program_id = Pubkey::from_str("YOUR_PROGRAM_ID).unwrap(); + } +} +``` + +Run the client script. + +```shell filename="Terminal" +cargo run --example client +``` + +Example output: + +``` +Transaction Signature: 54TWxKi3Jsi3UTeZbhLGUFX6JQH7TspRJjRRFZ8NFnwG5BXM9udxiX77bAACjKAS9fGnVeEazrXL4SfKrW7xZFYV +``` + +Ви можете перевірити підпис транзакції на +[Solana Explorer](https://explorer.solana.com/?cluster=custom&customUrl=http%3A%2F%2Flocalhost%3A8899) +(локальний кластер), щоб побачити "Hello, world!" в журналі програми. + +### Оновлення програми + +Програми Solana можна оновити, повторно розгорнувши їх на той самий ID програми. +Оновіть програму в `src/lib.rs`, щоб виводити "Hello, Solana!" замість "Hello, +world!". + +```diff filename="lib.rs" +pub fn process_instruction( + _program_id: &Pubkey, + _accounts: &[AccountInfo], + _instruction_data: &[u8], +) -> ProgramResult { +- msg!("Hello, world!"); ++ msg!("Hello, Solana!"); + Ok(()) +} +``` + +Протестуйте оновлену програму, виконавши команду `cargo test-sbf`. + +```shell filename="Terminal" +cargo test-sbf +``` + +Ви повинні побачити "Hello, Solana!" в журналі програми. + +```shell filename="Terminal" {4} +running 1 test +[2024-10-23T19:28:28.842639000Z INFO solana_program_test] "hello_world" SBF program from /code/misc/delete/hello_world/target/deploy/hello_world.so, modified 4 minutes, 31 seconds, 435 ms, 566 µs and 766 ns ago +[2024-10-23T19:28:28.934854000Z DEBUG solana_runtime::message_processor::stable_log] Program 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM invoke [1] +[2024-10-23T19:28:28.936735000Z DEBUG solana_runtime::message_processor::stable_log] Program log: Hello, Solana! +[2024-10-23T19:28:28.938774000Z DEBUG solana_runtime::message_processor::stable_log] Program 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM consumed 140 of 200000 compute units +[2024-10-23T19:28:28.938793000Z DEBUG solana_runtime::message_processor::stable_log] Program 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM success +test test::test_hello_world ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.14s +``` + +Виконайте команду `cargo build-sbf`, щоб згенерувати оновлений файл `.so`. + +```shell filename="Terminal" +cargo build-sbf +``` + +Повторно розгорніть програму за допомогою команди `solana program deploy`. + +```shell filename="Terminal" +solana program deploy ./target/deploy/hello_world.so +``` + +Знову виконайте клієнтський код і перевірте підпис транзакції на Solana +Explorer, щоб побачити "Hello, Solana!" в журналі програми. + +```shell filename="Terminal" +cargo run --example client +``` + +### Закриття програми + +Ви можете закрити свою програму Solana, щоб повернути SOL, виділені для акаунту. +Закриття програми є незворотним, тому це слід робити обережно. + +Щоб закрити програму, використовуйте команду +`solana program close `. Наприклад: + +```shell filename="Terminal" +solana program close 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz +--bypass-warning +``` + +Example output: + +``` +Closed Program Id 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz, 0.1350588 SOL +reclaimed +``` + +Зверніть увагу, що після закриття програми її ID програми не можна буде +використовувати знову. Спроба розгорнути програму з раніше закритим ID програми +призведе до помилки. + +``` +Error: Program 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz has been closed, use +a new Program Id +``` + +Якщо вам потрібно повторно розгорнути програму з тим самим вихідним кодом після +закриття програми, ви повинні згенерувати новий ID програми. Щоб згенерувати +нову ключову пару для програми, виконайте наступну команду: + +```shell filename="Terminal" +solana-keygen new -o ./target/deploy/hello_world-keypair.json --force +``` + +Альтернативно, ви можете видалити існуючий файл ключової пари (наприклад, +`./target/deploy/hello_world-keypair.json`) і знову виконати команду +`cargo build-sbf`, що згенерує новий файл ключової пари. + + diff --git a/docs/locales/uk/programs/rust/program-structure.md b/docs/locales/uk/programs/rust/program-structure.md new file mode 100644 index 000000000..e8d172094 --- /dev/null +++ b/docs/locales/uk/programs/rust/program-structure.md @@ -0,0 +1,1401 @@ +--- +title: Структура програми на Rust +sidebarLabel: Структура програми +description: + Дізнайтесь, як структуровані програми Solana на Rust, включаючи точки входу, + управління станом, обробку інструкцій та тестування. +sidebarSortOrder: 1 +--- + +Програми Solana, написані на Rust, мають мінімальні вимоги до структури, що дає +гнучкість у тому, як організовувати код. Єдина вимога — програма повинна мати +`entrypoint`, який визначає точку початку виконання програми. + +## Структура програми + +Хоча немає строгих правил для структури файлів, програми Solana зазвичай +дотримуються загального шаблону: + +- `entrypoint.rs`: Визначає точку входу, яка маршрутизує вхідні інструкції. +- `state.rs`: Визначає стан програми (дані акаунтів). +- `instructions.rs`: Визначає інструкції, які програма може виконувати. +- `processor.rs`: Визначає обробники інструкцій (функції), які реалізують + бізнес-логіку для кожної інструкції. +- `error.rs`: Визначає користувацькі помилки, які програма може повернути. + +Приклади можна знайти в +[Solana Program Library](https://github.com/solana-labs/solana-program-library/tree/master/token/program/src). + +## Приклад програми + +Щоб продемонструвати, як побудувати рідну програму на Rust з кількома +інструкціями, ми розглянемо просту програму лічильника, яка реалізує дві +інструкції: + +1. `InitializeCounter`: Створює і ініціалізує новий акаунт з початковим + значенням. +2. `IncrementCounter`: Збільшує значення, що зберігається в існуючому акаунті. + +Для простоти програма буде реалізована в одному файлі `lib.rs`, хоча на практиці +вам, можливо, захочеться розділити більші програми на кілька файлів. + + + + +```rs filename="lib.rs" +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint, + entrypoint::ProgramResult, + msg, + program::invoke, + program_error::ProgramError, + pubkey::Pubkey, + system_instruction, + sysvar::{rent::Rent, Sysvar}, +}; + +// Program entrypoint +entrypoint!(process_instruction); + +// Function to route instructions to the correct handler +pub fn process_instruction( + program_id: &Pubkey, + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> ProgramResult { + // Unpack instruction data + let instruction = CounterInstruction::unpack(instruction_data)?; + + // Match instruction type + match instruction { + CounterInstruction::InitializeCounter { initial_value } => { + process_initialize_counter(program_id, accounts, initial_value)? + } + CounterInstruction::IncrementCounter => process_increment_counter(program_id, accounts)?, + }; + Ok(()) +} + +// Instructions that our program can execute +#[derive(BorshSerialize, BorshDeserialize, Debug)] +pub enum CounterInstruction { + InitializeCounter { initial_value: u64 }, // variant 0 + IncrementCounter, // variant 1 +} + +impl CounterInstruction { + pub fn unpack(input: &[u8]) -> Result { + // Get the instruction variant from the first byte + let (&variant, rest) = input + .split_first() + .ok_or(ProgramError::InvalidInstructionData)?; + + // Match instruction type and parse the remaining bytes based on the variant + match variant { + 0 => { + // For InitializeCounter, parse a u64 from the remaining bytes + let initial_value = u64::from_le_bytes( + rest.try_into() + .map_err(|_| ProgramError::InvalidInstructionData)?, + ); + Ok(Self::InitializeCounter { initial_value }) + } + 1 => Ok(Self::IncrementCounter), // No additional data needed + _ => Err(ProgramError::InvalidInstructionData), + } + } +} + +// Initialize a new counter account +fn process_initialize_counter( + program_id: &Pubkey, + accounts: &[AccountInfo], + initial_value: u64, +) -> ProgramResult { + let accounts_iter = &mut accounts.iter(); + + let counter_account = next_account_info(accounts_iter)?; + let payer_account = next_account_info(accounts_iter)?; + let system_program = next_account_info(accounts_iter)?; + + // Size of our counter account + let account_space = 8; // Size in bytes to store a u64 + + // Calculate minimum balance for rent exemption + let rent = Rent::get()?; + let required_lamports = rent.minimum_balance(account_space); + + // Create the counter account + invoke( + &system_instruction::create_account( + payer_account.key, // Account paying for the new account + counter_account.key, // Account to be created + required_lamports, // Amount of lamports to transfer to the new account + account_space as u64, // Size in bytes to allocate for the data field + program_id, // Set program owner to our program + ), + &[ + payer_account.clone(), + counter_account.clone(), + system_program.clone(), + ], + )?; + + // Create a new CounterAccount struct with the initial value + let counter_data = CounterAccount { + count: initial_value, + }; + + // Get a mutable reference to the counter account's data + let mut account_data = &mut counter_account.data.borrow_mut()[..]; + + // Serialize the CounterAccount struct into the account's data + counter_data.serialize(&mut account_data)?; + + msg!("Counter initialized with value: {}", initial_value); + + Ok(()) +} + +// Update an existing counter's value +fn process_increment_counter(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { + let accounts_iter = &mut accounts.iter(); + let counter_account = next_account_info(accounts_iter)?; + + // Verify account ownership + if counter_account.owner != program_id { + return Err(ProgramError::IncorrectProgramId); + } + + // Mutable borrow the account data + let mut data = counter_account.data.borrow_mut(); + + // Deserialize the account data into our CounterAccount struct + let mut counter_data: CounterAccount = CounterAccount::try_from_slice(&data)?; + + // Increment the counter value + counter_data.count = counter_data + .count + .checked_add(1) + .ok_or(ProgramError::InvalidAccountData)?; + + // Serialize the updated counter data back into the account + counter_data.serialize(&mut &mut data[..])?; + + msg!("Counter incremented to: {}", counter_data.count); + Ok(()) +} + +// Struct representing our counter account's data +#[derive(BorshSerialize, BorshDeserialize, Debug)] +pub struct CounterAccount { + count: u64, +} + +#[cfg(test)] +mod test { + use super::*; + use solana_program_test::*; + use solana_sdk::{ + instruction::{AccountMeta, Instruction}, + signature::{Keypair, Signer}, + system_program, + transaction::Transaction, + }; + + #[tokio::test] + async fn test_counter_program() { + let program_id = Pubkey::new_unique(); + let (mut banks_client, payer, recent_blockhash) = ProgramTest::new( + "counter_program", + program_id, + processor!(process_instruction), + ) + .start() + .await; + + // Create a new keypair to use as the address for our counter account + let counter_keypair = Keypair::new(); + let initial_value: u64 = 42; + + // Step 1: Initialize the counter + println!("Testing counter initialization..."); + + // Create initialization instruction + let mut init_instruction_data = vec![0]; // 0 = initialize instruction + init_instruction_data.extend_from_slice(&initial_value.to_le_bytes()); + + let initialize_instruction = Instruction::new_with_bytes( + program_id, + &init_instruction_data, + vec![ + AccountMeta::new(counter_keypair.pubkey(), true), + AccountMeta::new(payer.pubkey(), true), + AccountMeta::new_readonly(system_program::id(), false), + ], + ); + + // Send transaction with initialize instruction + let mut transaction = + Transaction::new_with_payer(&[initialize_instruction], Some(&payer.pubkey())); + transaction.sign(&[&payer, &counter_keypair], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); + + // Check account data + let account = banks_client + .get_account(counter_keypair.pubkey()) + .await + .expect("Failed to get counter account"); + + if let Some(account_data) = account { + let counter: CounterAccount = CounterAccount::try_from_slice(&account_data.data) + .expect("Failed to deserialize counter data"); + assert_eq!(counter.count, 42); + println!( + "✅ Counter initialized successfully with value: {}", + counter.count + ); + } + + // Step 2: Increment the counter + println!("Testing counter increment..."); + + // Create increment instruction + let increment_instruction = Instruction::new_with_bytes( + program_id, + &[1], // 1 = increment instruction + vec![AccountMeta::new(counter_keypair.pubkey(), true)], + ); + + // Send transaction with increment instruction + let mut transaction = + Transaction::new_with_payer(&[increment_instruction], Some(&payer.pubkey())); + transaction.sign(&[&payer, &counter_keypair], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); + + // Check account data + let account = banks_client + .get_account(counter_keypair.pubkey()) + .await + .expect("Failed to get counter account"); + + if let Some(account_data) = account { + let counter: CounterAccount = CounterAccount::try_from_slice(&account_data.data) + .expect("Failed to deserialize counter data"); + assert_eq!(counter.count, 43); + println!("✅ Counter incremented successfully to: {}", counter.count); + } + } +} +``` + +```toml filename="Cargo.toml" +[package] +name = "counter_program" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] + +[dependencies] +borsh = "1.5.1" +solana-program = "1.18.26" + +[dev-dependencies] +solana-program-test = "1.18.26" +solana-sdk = "1.18.26" +tokio = "1.41.0" +``` + + + + + + +### Створення нової програми + +Спочатку створіть новий проект на Rust, використовуючи стандартну команду +`cargo init` з прапорцем `--lib`. + +```shell filename="Terminal" +cargo init counter_program --lib +``` + +Перейдіть до директорії проекту. Ви повинні побачити стандартні файли +`src/lib.rs` та `Cargo.toml`. + +```shell filename="Terminal" +cd counter_program +``` + +Далі додайте залежність `solana-program`. Це мінімальна залежність, необхідна +для побудови програми Solana. + +```shell filename="Terminal" +cargo add solana-program@1.18.26 +``` + +Далі додайте наступний фрагмент до файлу `Cargo.toml`. Якщо ви не включите цю +конфігурацію, директорія `target/deploy` не буде згенерована під час збірки +програми. + +```toml filename="Cargo.toml" +[lib] +crate-type = ["cdylib", "lib"] +``` + +Ваш файл `Cargo.toml` повинен виглядати наступним чином: + +```toml filename="Cargo.toml" +[package] +name = "counter_program" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] + +[dependencies] +solana-program = "1.18.26" +``` + +### Точка входу програми + +Точка входу програми Solana — це функція, яка викликається, коли програма +активується. Точка входу має наступне сире визначення, і розробники можуть +створювати власну реалізацію функції точки входу. + +Для простоти використовуйте макрос +[`entrypoint!`](https://github.com/solana-labs/solana/blob/v2.0/sdk/program/src/entrypoint.rs#L124-L140) +з бібліотеки `solana_program` для визначення точки входу у вашій програмі. + +```rs +#[no_mangle] +pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64; +``` + +Замініть стандартний код у файлі `lib.rs` на наступний код. Цей фрагмент: + +1. Імпортує необхідні залежності з `solana_program` +2. Визначає точку входу програми за допомогою макросу `entrypoint!` +3. Реалізує функцію `process_instruction`, яка маршрутизує інструкції до + відповідних функцій обробників + +```rs filename="lib.rs" {13} /process_instruction/ +use solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint, + entrypoint::ProgramResult, + msg, + program::invoke, + program_error::ProgramError, + pubkey::Pubkey, + system_instruction, + sysvar::{rent::Rent, Sysvar}, +}; + +entrypoint!(process_instruction); + +pub fn process_instruction( + program_id: &Pubkey, + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> ProgramResult { + // Your program logic + Ok(()) +} +``` + +Макрос `entrypoint!` вимагає функцію з наступним +[типом підпису](https://github.com/solana-labs/solana/blob/v2.0/sdk/program/src/entrypoint.rs#L28-L29) +як аргумент: + +```rs +pub type ProcessInstruction = + fn(program_id: &Pubkey, accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult; +``` + +Коли програма Solana викликається, точка входу +[десеріалізує](https://github.com/solana-labs/solana/blob/v2.0/sdk/program/src/entrypoint.rs#L277) +[вхідні дані](https://github.com/solana-labs/solana/blob/v2.0/sdk/program/src/entrypoint.rs#L129-L131) +(надані як байти) у три значення та передає їх до функції +[`process_instruction`](https://github.com/solana-labs/solana/blob/v2.0/sdk/program/src/entrypoint.rs#L132): + +- `program_id`: Публічний ключ викликаної програми (поточна програма) +- `accounts`: `AccountInfo` для акаунтів, необхідних для викликаної інструкції +- `instruction_data`: Додаткові дані, передані програмі, які вказують інструкцію + для виконання та її необхідні аргументи + +Ці три параметри безпосередньо відповідають даним, які клієнти повинні надати +при побудові інструкції для виклику програми. + +### Визначення стану програми + +При створенні програми Solana зазвичай починають з визначення стану програми — +даних, які будуть зберігатися в акаунтах, створених і належних вашій програмі. + +Стан програми визначається за допомогою структур Rust, які представляють макет +даних акаунтів програми. Ви можете визначити кілька структур для представлення +різних типів акаунтів вашої програми. + +При роботі з акаунтами вам потрібен спосіб перетворювати типи даних вашої +програми в і з сирих байтів, що зберігаються в полі даних акаунту: + +- Серіалізація: Перетворення ваших типів даних у байти для збереження в полі + даних акаунту +- Десеріалізація: Перетворення байтів, збережених в акаунті, назад у ваші типи + даних + +Хоча ви можете використовувати будь-який формат серіалізації для розробки +програм Solana, [Borsh](https://borsh.io/) є загальноприйнятим. Щоб +використовувати Borsh у вашій програмі Solana: + +1. Додайте crate `borsh` як залежність до вашого `Cargo.toml`: + +```shell filename="Terminal" +cargo add borsh +``` + +2. Імпортуйте трейди Borsh і використовуйте макрос `derive`, щоб реалізувати + трейди для ваших структур: + +```rust +use borsh::{BorshSerialize, BorshDeserialize}; + +// Define struct representing our counter account's data +#[derive(BorshSerialize, BorshDeserialize, Debug)] +pub struct CounterAccount { + count: u64, +} +``` + +Додайте структуру `CounterAccount` до файлу `lib.rs` для визначення стану +програми. Ця структура буде використовуватися як в інструкції ініціалізації, так +і в інструкції збільшення. + +```rs filename="lib.rs" {12} {25-29} +use solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint, + entrypoint::ProgramResult, + msg, + program::invoke, + program_error::ProgramError, + pubkey::Pubkey, + system_instruction, + sysvar::{rent::Rent, Sysvar}, +}; +use borsh::{BorshSerialize, BorshDeserialize}; + +entrypoint!(process_instruction); + +pub fn process_instruction( + program_id: &Pubkey, + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> ProgramResult { + // Your program logic + Ok(()) +} + +#[derive(BorshSerialize, BorshDeserialize, Debug)] +pub struct CounterAccount { + count: u64, +} +``` + +### Визначення інструкцій + +Інструкції позначають різні операції, які ваша програма Solana може виконувати. +Вважайте їх публічними API вашої програми — вони визначають, які дії користувачі +можуть виконувати при взаємодії з вашою програмою. + +Інструкції зазвичай визначаються за допомогою enum на Rust, де: + +- Кожен варіант enum представляє різну інструкцію +- Payload варіанту представляє параметри інструкції + +Зверніть увагу, що варіанти enum на Rust автоматично нумеруються, починаючи з 0. + +Нижче наведено приклад enum, що визначає дві інструкції: + +```rust +#[derive(BorshSerialize, BorshDeserialize, Debug)] +pub enum CounterInstruction { + InitializeCounter { initial_value: u64 }, // variant 0 + IncrementCounter, // variant 1 +} +``` + +Коли клієнт викликає вашу програму, він повинен надати дані інструкції (як буфер +байтів), де: + +- Перший байт вказує, який варіант інструкції потрібно виконати (0, 1 і т.д.) +- Решта байтів містить серіалізовані параметри інструкції (якщо це необхідно) + +Для перетворення даних інструкції (байтів) у варіант enum зазвичай реалізують +допоміжний метод. Цей метод: + +1. Розділяє перший байт, щоб отримати варіант інструкції +2. Зіставляє варіант і парсить будь-які додаткові параметри з решти байтів +3. Повертає відповідний варіант enum + +Наприклад, метод `unpack` для enum `CounterInstruction`: + +```rust +impl CounterInstruction { + pub fn unpack(input: &[u8]) -> Result { + // Get the instruction variant from the first byte + let (&variant, rest) = input + .split_first() + .ok_or(ProgramError::InvalidInstructionData)?; + + // Match instruction type and parse the remaining bytes based on the variant + match variant { + 0 => { + // For InitializeCounter, parse a u64 from the remaining bytes + let initial_value = u64::from_le_bytes( + rest.try_into() + .map_err(|_| ProgramError::InvalidInstructionData)? + ); + Ok(Self::InitializeCounter { initial_value }) + } + 1 => Ok(Self::IncrementCounter), // No additional data needed + _ => Err(ProgramError::InvalidInstructionData), + } + } +} +``` + +Додайте наступний код до файлу `lib.rs` для визначення інструкцій для програми +лічильника. + +```rs filename="lib.rs" {18-46} +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::{ + account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, msg, + program_error::ProgramError, pubkey::Pubkey, +}; + +entrypoint!(process_instruction); + +pub fn process_instruction( + program_id: &Pubkey, + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> ProgramResult { + // Your program logic + Ok(()) +} + +#[derive(BorshSerialize, BorshDeserialize, Debug)] +pub enum CounterInstruction { + InitializeCounter { initial_value: u64 }, // variant 0 + IncrementCounter, // variant 1 +} + +impl CounterInstruction { + pub fn unpack(input: &[u8]) -> Result { + // Get the instruction variant from the first byte + let (&variant, rest) = input + .split_first() + .ok_or(ProgramError::InvalidInstructionData)?; + + // Match instruction type and parse the remaining bytes based on the variant + match variant { + 0 => { + // For InitializeCounter, parse a u64 from the remaining bytes + let initial_value = u64::from_le_bytes( + rest.try_into() + .map_err(|_| ProgramError::InvalidInstructionData)?, + ); + Ok(Self::InitializeCounter { initial_value }) + } + 1 => Ok(Self::IncrementCounter), // No additional data needed + _ => Err(ProgramError::InvalidInstructionData), + } + } +} +``` + +### Обробники інструкцій + +Обробники інструкцій — це функції, які містять бізнес-логіку для кожної +інструкції. Зазвичай функції обробників називаються як +`process_`, але ви вільні вибрати будь-яку конвенцію +найменувань. + +Додайте наступний код до файлу `lib.rs`. Цей код використовує enum +`CounterInstruction` та метод `unpack`, визначений на попередньому кроці, для +маршрутизації вхідних інструкцій до відповідних функцій обробників: + +```rs filename="lib.rs" {8-17} {20-32} /process_initialize_counter/1 /process_increment_counter/1 +entrypoint!(process_instruction); + +pub fn process_instruction( + program_id: &Pubkey, + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> ProgramResult { + // Unpack instruction data + let instruction = CounterInstruction::unpack(instruction_data)?; + + // Match instruction type + match instruction { + CounterInstruction::InitializeCounter { initial_value } => { + process_initialize_counter(program_id, accounts, initial_value)? + } + CounterInstruction::IncrementCounter => process_increment_counter(program_id, accounts)?, + }; +} + +fn process_initialize_counter( + program_id: &Pubkey, + accounts: &[AccountInfo], + initial_value: u64, +) -> ProgramResult { + // Implementation details... + Ok(()) +} + +fn process_increment_counter(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { + // Implementation details... + Ok(()) +} +``` + +Далі додайте реалізацію функції `process_initialize_counter`. Цей обробник +інструкції: + +1. Створює і виділяє місце для нового акаунту для збереження даних лічильника +2. Ініціалізує дані акаунту з `initial_value`, переданим в інструкцію + + + + +Функція `process_initialize_counter` вимагає три акаунти: + +1. Акаунт лічильника, який буде створено та ініціалізовано +2. Акаунт платника, який профінансує створення нового акаунту +3. System Program, який ми викликаємо для створення нового акаунту + +Для визначення акаунтів, необхідних для інструкції, ми створюємо ітератор по +масиву `accounts` та використовуємо функцію `next_account_info`, щоб отримати +кожен акаунт. Кількість акаунтів, яку ви визначаєте, є кількістю акаунтів, +необхідних для інструкції. + +Порядок акаунтів має значення — при побудові інструкції на стороні клієнта, +акаунти повинні надаватися в тому ж порядку, в якому вони визначені в програмі, +щоб інструкція виконалася успішно. + +Хоча змінні імена акаунтів не впливають на функціональність програми, +рекомендується використовувати описові імена. + +```rs filename="lib.rs" {6-10} +fn process_initialize_counter( + program_id: &Pubkey, + accounts: &[AccountInfo], + initial_value: u64, +) -> ProgramResult { + let accounts_iter = &mut accounts.iter(); + + let counter_account = next_account_info(accounts_iter)?; + let payer_account = next_account_info(accounts_iter)?; + let system_program = next_account_info(accounts_iter)?; + + Ok(()) +} +``` + +Перед створенням акаунту нам потрібно: + +1. Вказати простір (у байтах), який потрібно виділити для поля даних акаунту. + Оскільки ми зберігаємо значення типу u64 (`count`), нам потрібно 8 байтів. + +2. Обчислити мінімальний баланс "ренту", необхідний для акаунту. На Solana + акаунти повинні підтримувати мінімальний баланс лампортів (ренту), що + залежить від кількості даних, що зберігаються в акаунті. + +```rs filename="lib.rs" {12-17} +fn process_initialize_counter( + program_id: &Pubkey, + accounts: &[AccountInfo], + initial_value: u64, +) -> ProgramResult { + let accounts_iter = &mut accounts.iter(); + + let counter_account = next_account_info(accounts_iter)?; + let payer_account = next_account_info(accounts_iter)?; + let system_program = next_account_info(accounts_iter)?; + + // Size of our counter account + let account_space = 8; // Size in bytes to store a u64 + + // Calculate minimum balance for rent exemption + let rent = Rent::get()?; + let required_lamports = rent.minimum_balance(account_space); + + Ok(()) +} +``` + +Після того, як простір визначено і рент обчислений, створіть акаунт, викликавши +інструкцію `create_account` з System Program. + +На Solana нові акаунти можуть бути створені тільки через System Program. При +створенні акаунту ми вказуємо кількість байтів для виділення та +програму-власника нового акаунту. System Program: + +1. Створює новий акаунт +2. Виділяє вказаний простір для поля даних акаунту +3. Передає право власності на вказану програму + +Цей перехід права власності важливий, оскільки тільки власник акаунту може +змінювати дані акаунту. У цьому випадку ми встановлюємо нашу програму як +власника, що дозволить нам змінювати дані акаунту для збереження значення +лічильника. + +Щоб викликати System Program з інструкції нашої програми, ми робимо Cross +Program Invocation (CPI) через функцію `invoke`. CPI дозволяє одній програмі +викликати інструкції інших програм — в цьому випадку інструкцію `create_account` +з System Program. + +```rs filename="lib.rs" {19-33} +fn process_initialize_counter( + program_id: &Pubkey, + accounts: &[AccountInfo], + initial_value: u64, +) -> ProgramResult { + let accounts_iter = &mut accounts.iter(); + + let counter_account = next_account_info(accounts_iter)?; + let payer_account = next_account_info(accounts_iter)?; + let system_program = next_account_info(accounts_iter)?; + + // Size of our counter account + let account_space = 8; // Size in bytes to store a u64 + + // Calculate minimum balance for rent exemption + let rent = Rent::get()?; + let required_lamports = rent.minimum_balance(account_space); + + // Create the counter account + invoke( + &system_instruction::create_account( + payer_account.key, // Account paying for the new account + counter_account.key, // Account to be created + required_lamports, // Amount of lamports to transfer to the new account + account_space as u64, // Size in bytes to allocate for the data field + program_id, // Set program owner to our program + ), + &[ + payer_account.clone(), + counter_account.clone(), + system_program.clone(), + ], + )?; + + Ok(()) +} +``` + +Після того, як акаунт створено, ми ініціалізуємо дані акаунту за допомогою: + +1. Створення нової структури `CounterAccount` з переданим значенням + `initial_value`. +2. Отримання змінної посилання на поле даних нового акаунту. +3. Серіалізації структури `CounterAccount` в поле даних акаунту, що ефективно + зберігає значення `initial_value` в акаунті. + +```rs filename="lib.rs" {35-44} /initial_value/ +fn process_initialize_counter( + program_id: &Pubkey, + accounts: &[AccountInfo], + initial_value: u64, +) -> ProgramResult { + let accounts_iter = &mut accounts.iter(); + + let counter_account = next_account_info(accounts_iter)?; + let payer_account = next_account_info(accounts_iter)?; + let system_program = next_account_info(accounts_iter)?; + + // Size of our counter account + let account_space = 8; // Size in bytes to store a u64 + + // Calculate minimum balance for rent exemption + let rent = Rent::get()?; + let required_lamports = rent.minimum_balance(account_space); + + // Create the counter account + invoke( + &system_instruction::create_account( + payer_account.key, // Account paying for the new account + counter_account.key, // Account to be created + required_lamports, // Amount of lamports to transfer to the new account + account_space as u64, // Size in bytes to allocate for the data field + program_id, // Set program owner to our program + ), + &[ + payer_account.clone(), + counter_account.clone(), + system_program.clone(), + ], + )?; + + // Create a new CounterAccount struct with the initial value + let counter_data = CounterAccount { + count: initial_value, + }; + + // Get a mutable reference to the counter account's data + let mut account_data = &mut counter_account.data.borrow_mut()[..]; + + // Serialize the CounterAccount struct into the account's data + counter_data.serialize(&mut account_data)?; + + msg!("Counter initialized with value: {}", initial_value); + + Ok(()) +} +``` + + + + +```rs filename="lib.rs" +// Initialize a new counter account +fn process_initialize_counter( + program_id: &Pubkey, + accounts: &[AccountInfo], + initial_value: u64, +) -> ProgramResult { + let accounts_iter = &mut accounts.iter(); + + let counter_account = next_account_info(accounts_iter)?; + let payer_account = next_account_info(accounts_iter)?; + let system_program = next_account_info(accounts_iter)?; + + // Size of our counter account + let account_space = 8; // Size in bytes to store a u64 + + // Calculate minimum balance for rent exemption + let rent = Rent::get()?; + let required_lamports = rent.minimum_balance(account_space); + + // Create the counter account + invoke( + &system_instruction::create_account( + payer_account.key, // Account paying for the new account + counter_account.key, // Account to be created + required_lamports, // Amount of lamports to transfer to the new account + account_space as u64, // Size in bytes to allocate for the data field + program_id, // Set program owner to our program + ), + &[ + payer_account.clone(), + counter_account.clone(), + system_program.clone(), + ], + )?; + + // Create a new CounterAccount struct with the initial value + let counter_data = CounterAccount { + count: initial_value, + }; + + // Get a mutable reference to the counter account's data + let mut account_data = &mut counter_account.data.borrow_mut()[..]; + + // Serialize the CounterAccount struct into the account's data + counter_data.serialize(&mut account_data)?; + + msg!("Counter initialized with value: {}", initial_value); + + Ok(()) +} +``` + +Далі додайте реалізацію функції `process_increment_counter`. Ця інструкція +збільшує значення існуючого акаунту лічильника. + + + + +Так само, як і в функції `process_initialize_counter`, ми починаємо з створення +ітератора по акаунтах. У цьому випадку ми очікуємо лише один акаунт, який є +акаунтом, що має бути оновлений. + +Зверніть увагу, що на практиці розробник повинен реалізувати різні перевірки +безпеки для валідності акаунтів, переданих до програми. Оскільки всі акаунти +надаються викликачем інструкції, немає гарантії, що надані акаунти — це саме ті +акаунти, які програма очікує. Відсутність перевірок валідності акаунтів є +поширеним джерелом вразливостей програми. + +Наведений приклад містить перевірку для того, щоб переконатися, що акаунт, на +який ми посилаємось як `counter_account`, належить виконуючій програмі. + +```rs filename="lib.rs" {6-9} +// Update an existing counter's value +fn process_increment_counter(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { + let accounts_iter = &mut accounts.iter(); + let counter_account = next_account_info(accounts_iter)?; + + // Verify account ownership + if counter_account.owner != program_id { + return Err(ProgramError::IncorrectProgramId); + } + + Ok(()) +} +``` + +Щоб оновити дані акаунту, ми: + +- Змінно позичаємо поле даних існуючого акаунту +- Десеріалізуємо сирі байти в нашу структуру `CounterAccount` +- Оновлюємо значення `count` +- Серіалізуємо змінену структуру назад у поле даних акаунту + +```rs filename="lib.rs" {11-24} +// Update an existing counter's value +fn process_increment_counter(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { + let accounts_iter = &mut accounts.iter(); + let counter_account = next_account_info(accounts_iter)?; + + // Verify account ownership + if counter_account.owner != program_id { + return Err(ProgramError::IncorrectProgramId); + } + + // Mutable borrow the account data + let mut data = counter_account.data.borrow_mut(); + + // Deserialize the account data into our CounterAccount struct + let mut counter_data: CounterAccount = CounterAccount::try_from_slice(&data)?; + + // Increment the counter value + counter_data.count = counter_data + .count + .checked_add(1) + .ok_or(ProgramError::InvalidAccountData)?; + + // Serialize the updated counter data back into the account + counter_data.serialize(&mut &mut data[..])?; + + msg!("Counter incremented to: {}", counter_data.count); + Ok(()) +} +``` + + + + +```rs filename="lib.rs" +// Update an existing counter's value +fn process_increment_counter(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { + let accounts_iter = &mut accounts.iter(); + let counter_account = next_account_info(accounts_iter)?; + + // Verify account ownership + if counter_account.owner != program_id { + return Err(ProgramError::IncorrectProgramId); + } + + // Mutable borrow the account data + let mut data = counter_account.data.borrow_mut(); + + // Deserialize the account data into our CounterAccount struct + let mut counter_data: CounterAccount = CounterAccount::try_from_slice(&data)?; + + // Increment the counter value + counter_data.count = counter_data + .count + .checked_add(1) + .ok_or(ProgramError::InvalidAccountData)?; + + // Serialize the updated counter data back into the account + counter_data.serialize(&mut &mut data[..])?; + + msg!("Counter incremented to: {}", counter_data.count); + Ok(()) +} +``` + +### Тестування інструкцій + +Для тестування інструкцій програми додайте наступні залежності до файлу +`Cargo.toml`. + +```shell filename="Terminal" +cargo add solana-program-test@1.18.26 --dev +cargo add solana-sdk@1.18.26 --dev +cargo add tokio --dev +``` + +Далі додайте наступний тестовий модуль до файлу `lib.rs` і виконайте команду +`cargo test-sbf` для запуску тестів. За бажанням, використовуйте прапорець +`--nocapture`, щоб побачити виведені дані в результатах. + +```shell filename="Термінал" +cargo test-sbf -- --nocapture +``` + + + + +Спочатку налаштуйте тестовий модуль і імпортуйте необхідні залежності: + +```rs filename="lib.rs" +#[cfg(test)] +mod test { + use super::*; + use solana_program_test::*; + use solana_sdk::{ + instruction::{AccountMeta, Instruction}, + signature::{Keypair, Signer}, + system_program, + transaction::Transaction, + }; + + #[tokio::test] + async fn test_counter_program() { + // Test code will go here + } +} +``` + +Далі налаштуйте тест за допомогою `ProgramTest`. Потім створіть нову ключову +пару, яку будемо використовувати як адресу для акаунту лічильника, який ми +ініціалізуємо, і визначте початкове значення, яке встановимо для лічильника. + +```rs filename="lib.rs" +#[cfg(test)] +mod test { + use super::*; + use solana_program_test::*; + use solana_sdk::{ + instruction::{AccountMeta, Instruction}, + signature::{Keypair, Signer}, + system_program, + transaction::Transaction, + }; + + #[tokio::test] + async fn test_counter_program() { + let program_id = Pubkey::new_unique(); + let (mut banks_client, payer, recent_blockhash) = ProgramTest::new( + "counter_program", + program_id, + processor!(process_instruction), + ) + .start() + .await; + + // Create a new keypair to use as the address for our counter account + let counter_keypair = Keypair::new(); + let initial_value: u64 = 42; + } +} +``` + +При побудові інструкції кожен акаунт повинен бути наданий як +[`AccountMeta`](https://github.com/solana-labs/solana/blob/v2.0/sdk/program/src/instruction.rs#L539-L545), +який вказує: + +- Публічний ключ акаунту (`Pubkey`) +- `is_writable`: Чи будуть змінюватися дані акаунту +- `is_signer`: Чи повинен акаунт підписати транзакцію + +```rs +AccountMeta::new(account1_pubkey, true), // writable, signer +AccountMeta::new(account2_pubkey, false), // writable, not signer +AccountMeta::new_readonly(account3_pubkey, false), // not writable, not signer +AccountMeta::new_readonly(account4_pubkey, true), // writable, signer +``` + +Для тестування інструкції ініціалізації: + +- Створіть дані інструкції з варіантом 0 (`InitializeCounter`) та початковим + значенням +- Побудуйте інструкцію з ID програми, даними інструкції та необхідними акаунтами +- Відправте транзакцію з інструкцією ініціалізації +- Перевірте, що акаунт був створений з правильним початковим значенням + +```rs filename="lib.rs" {16-53} + #[tokio::test] + async fn test_counter_program() { + let program_id = Pubkey::new_unique(); + let (mut banks_client, payer, recent_blockhash) = ProgramTest::new( + "counter_program", + program_id, + processor!(process_instruction), + ) + .start() + .await; + + // Create a new keypair to use as the address for our counter account + let counter_keypair = Keypair::new(); + let initial_value: u64 = 42; + + // Step 1: Initialize the counter + println!("Testing counter initialization..."); + + // Create initialization instruction + let mut init_instruction_data = vec![0]; // 0 = initialize instruction + init_instruction_data.extend_from_slice(&initial_value.to_le_bytes()); + + let initialize_instruction = Instruction::new_with_bytes( + program_id, + &init_instruction_data, + vec![ + AccountMeta::new(counter_keypair.pubkey(), true), + AccountMeta::new(payer.pubkey(), true), + AccountMeta::new_readonly(system_program::id(), false), + ], + ); + + // Send transaction with initialize instruction + let mut transaction = + Transaction::new_with_payer(&[initialize_instruction], Some(&payer.pubkey())); + transaction.sign(&[&payer, &counter_keypair], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); + + // Check account data + let account = banks_client + .get_account(counter_keypair.pubkey()) + .await + .expect("Failed to get counter account"); + + if let Some(account_data) = account { + let counter: CounterAccount = CounterAccount::try_from_slice(&account_data.data) + .expect("Failed to deserialize counter data"); + assert_eq!(counter.count, 42); + println!( + "✅ Counter initialized successfully with value: {}", + counter.count + ); + } + } +``` + +Для тестування інструкції збільшення: + +- Побудуйте інструкцію з ID програми, даними інструкції та необхідними акаунтами +- Відправте транзакцію з інструкцією збільшення +- Перевірте, що акаунт був збільшений до правильного значення + +Зверніть увагу, що дані інструкції для інструкції збільшення — це `[1]`, що +відповідає варіанту 1 (`IncrementCounter`). Оскільки інструкція збільшення не +має додаткових параметрів, дані — це просто варіант інструкції. + +```rs filename="lib.rs" {55-82} + #[tokio::test] + async fn test_counter_program() { + let program_id = Pubkey::new_unique(); + let (mut banks_client, payer, recent_blockhash) = ProgramTest::new( + "counter_program", + program_id, + processor!(process_instruction), + ) + .start() + .await; + + // Create a new keypair to use as the address for our counter account + let counter_keypair = Keypair::new(); + let initial_value: u64 = 42; + + // Step 1: Initialize the counter + println!("Testing counter initialization..."); + + // Create initialization instruction + let mut init_instruction_data = vec![0]; // 0 = initialize instruction + init_instruction_data.extend_from_slice(&initial_value.to_le_bytes()); + + let initialize_instruction = Instruction::new_with_bytes( + program_id, + &init_instruction_data, + vec![ + AccountMeta::new(counter_keypair.pubkey(), true), + AccountMeta::new(payer.pubkey(), true), + AccountMeta::new_readonly(system_program::id(), false), + ], + ); + + // Send transaction with initialize instruction + let mut transaction = + Transaction::new_with_payer(&[initialize_instruction], Some(&payer.pubkey())); + transaction.sign(&[&payer, &counter_keypair], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); + + // Check account data + let account = banks_client + .get_account(counter_keypair.pubkey()) + .await + .expect("Failed to get counter account"); + + if let Some(account_data) = account { + let counter: CounterAccount = CounterAccount::try_from_slice(&account_data.data) + .expect("Failed to deserialize counter data"); + assert_eq!(counter.count, 42); + println!( + "✅ Counter initialized successfully with value: {}", + counter.count + ); + } + + // Step 2: Increment the counter + println!("Testing counter increment..."); + + // Create increment instruction + let increment_instruction = Instruction::new_with_bytes( + program_id, + &[1], // 1 = increment instruction + vec![AccountMeta::new(counter_keypair.pubkey(), true)], + ); + + // Send transaction with increment instruction + let mut transaction = + Transaction::new_with_payer(&[increment_instruction], Some(&payer.pubkey())); + transaction.sign(&[&payer, &counter_keypair], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); + + // Check account data + let account = banks_client + .get_account(counter_keypair.pubkey()) + .await + .expect("Failed to get counter account"); + + if let Some(account_data) = account { + let counter: CounterAccount = CounterAccount::try_from_slice(&account_data.data) + .expect("Failed to deserialize counter data"); + assert_eq!(counter.count, 43); + println!("✅ Counter incremented successfully to: {}", counter.count); + } + } +``` + + + + +```rs filename="lib.rs" +#[cfg(test)] +mod test { + use super::*; + use solana_program_test::*; + use solana_sdk::{ + instruction::{AccountMeta, Instruction}, + signature::{Keypair, Signer}, + system_program, + transaction::Transaction, + }; + + #[tokio::test] + async fn test_counter_program() { + let program_id = Pubkey::new_unique(); + let (mut banks_client, payer, recent_blockhash) = ProgramTest::new( + "counter_program", + program_id, + processor!(process_instruction), + ) + .start() + .await; + + // Create a new keypair to use as the address for our counter account + let counter_keypair = Keypair::new(); + let initial_value: u64 = 42; + + // Step 1: Initialize the counter + println!("Testing counter initialization..."); + + // Create initialization instruction + let mut init_instruction_data = vec![0]; // 0 = initialize instruction + init_instruction_data.extend_from_slice(&initial_value.to_le_bytes()); + + let initialize_instruction = Instruction::new_with_bytes( + program_id, + &init_instruction_data, + vec![ + AccountMeta::new(counter_keypair.pubkey(), true), + AccountMeta::new(payer.pubkey(), true), + AccountMeta::new_readonly(system_program::id(), false), + ], + ); + + // Send transaction with initialize instruction + let mut transaction = + Transaction::new_with_payer(&[initialize_instruction], Some(&payer.pubkey())); + transaction.sign(&[&payer, &counter_keypair], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); + + // Check account data + let account = banks_client + .get_account(counter_keypair.pubkey()) + .await + .expect("Failed to get counter account"); + + if let Some(account_data) = account { + let counter: CounterAccount = CounterAccount::try_from_slice(&account_data.data) + .expect("Failed to deserialize counter data"); + assert_eq!(counter.count, 42); + println!( + "✅ Counter initialized successfully with value: {}", + counter.count + ); + } + + // Step 2: Increment the counter + println!("Testing counter increment..."); + + // Create increment instruction + let increment_instruction = Instruction::new_with_bytes( + program_id, + &[1], // 1 = increment instruction + vec![AccountMeta::new(counter_keypair.pubkey(), true)], + ); + + // Send transaction with increment instruction + let mut transaction = + Transaction::new_with_payer(&[increment_instruction], Some(&payer.pubkey())); + transaction.sign(&[&payer, &counter_keypair], recent_blockhash); + banks_client.process_transaction(transaction).await.unwrap(); + + // Check account data + let account = banks_client + .get_account(counter_keypair.pubkey()) + .await + .expect("Failed to get counter account"); + + if let Some(account_data) = account { + let counter: CounterAccount = CounterAccount::try_from_slice(&account_data.data) + .expect("Failed to deserialize counter data"); + assert_eq!(counter.count, 43); + println!("✅ Counter incremented successfully to: {}", counter.count); + } + } +} +``` + +Example output: + +```shell filename="Terminal" {6} {10} +running 1 test +[2024-10-29T20:51:13.783708000Z INFO solana_program_test] "counter_program" SBF program from /counter_program/target/deploy/counter_program.so, modified 2 seconds, 169 ms, 153 µs and 461 ns ago +[2024-10-29T20:51:13.855204000Z DEBUG solana_runtime::message_processor::stable_log] Program 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM invoke [1] +[2024-10-29T20:51:13.856052000Z DEBUG solana_runtime::message_processor::stable_log] Program 11111111111111111111111111111111 invoke [2] +[2024-10-29T20:51:13.856135000Z DEBUG solana_runtime::message_processor::stable_log] Program 11111111111111111111111111111111 success +[2024-10-29T20:51:13.856242000Z DEBUG solana_runtime::message_processor::stable_log] Program log: Counter initialized with value: 42 +[2024-10-29T20:51:13.856285000Z DEBUG solana_runtime::message_processor::stable_log] Program 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM consumed 3791 of 200000 compute units +[2024-10-29T20:51:13.856307000Z DEBUG solana_runtime::message_processor::stable_log] Program 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM success +[2024-10-29T20:51:13.860038000Z DEBUG solana_runtime::message_processor::stable_log] Program 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM invoke [1] +[2024-10-29T20:51:13.860333000Z DEBUG solana_runtime::message_processor::stable_log] Program log: Counter incremented to: 43 +[2024-10-29T20:51:13.860355000Z DEBUG solana_runtime::message_processor::stable_log] Program 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM consumed 756 of 200000 compute units +[2024-10-29T20:51:13.860375000Z DEBUG solana_runtime::message_processor::stable_log] Program 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM success +test test::test_counter_program ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.08s +``` + + diff --git a/docs/locales/uk/programs/testing.md b/docs/locales/uk/programs/testing.md new file mode 100644 index 000000000..2ec9784b0 --- /dev/null +++ b/docs/locales/uk/programs/testing.md @@ -0,0 +1,229 @@ +--- +title: "Тестування з NodeJS" +description: + "Тестування нативних solana programs написаних Rust використовуючи NodeJS" +sidebarSortOrder: 5 +--- + +## Тестування з NodeJS + +Коли ви розробляєте програми на Solana, важливо забезпечити їхню правильність і +надійність. До цього часу розробники використовували `solana-test-validator` для +тестування. Цей документ описує тестування вашої програми Solana за допомогою +Node.js і бібліотеки `solana-bankrun`. + +## Огляд + +Є два способи тестування програм на Solana: + +1. [solana-test-validator](https://docs.anza.xyz/cli/examples/test-validator): + Локальний емулятор блокчейна Solana, який обробляє транзакції, що + надсилаються на валідацію. +2. Різні фреймворки для тестування програм SBF (Solana Bytecode Format) на базі + BanksClient: + - `Bankrun` — це фреймворк, що імітує роботу Solana bank, дозволяючи + розробникам розгортати програми, взаємодіяти з ними та оцінювати їх + поведінку у тестових умовах, що нагадують mainnet. + - Підтримуються фреймворки як + [solana-program-test](https://docs.rs/solana-program-test) (Rust), + [solana-bankrun](https://github.com/kevinheavey/solana-bankrun) (Rust, + JavaScript), [anchor-bankrun](https://www.npmjs.com/package/anchor-bankrun) + (Anchor, JavaScript), + [solders.bankrun](https://kevinheavey.github.io/solders/api_reference/bankrun.html) + (Python). + +> [`pnpm create solana-program`](https://github.com/solana-program/create-solana-program) +> може +> допомогти створити клієнти для JS і Rust, включаючи тести. Anchor ще не +> підтримується. + +У цьому керівництві ми використовуємо `Solana Bankrun`. +`Bankrun` — це дуже швидкий, потужний та легкий фреймворк для тестування програм +Solana у Node.js. + +- Основна перевага використання `Solana Bankrun` полягає в тому, що вам не + потрібно налаштовувати середовище для тестування програм, як це потрібно при + використанні `solana-test-validator`. Це можна зробити за допомогою коду + всередині тестів. +- `Bankrun` динамічно встановлює час та дані акаунтів, що неможливо при + використанні `solana-test-validator`. + +## Інсталяція + +Додайте `solana-bankrun` як dev-залежність до вашого Node.js проекту. Якщо ваша +Solana програма ще не є Node.js проектом, ви можете ініціалізувати її за +допомогою команди `npm init`: + +```bash +npm i -D solana-bankrun +``` + +## Використання + +### Директорія для Програми + +Перш за все, `.so` файл вашої програми повинен бути присутнім в одній із +наступних директорій: + +- `./tests/fixtures` (створіть цю директорію, якщо її ще не існує). +- Ваша поточна робоча директорія. +- Директорія, яку ви визначите в змінних середовища `BPF_OUT_DIR` або + `SBF_OUT_DIR`. + Наприклад: + +```json +{ + "scripts": { + "test": "pnpm ts-mocha -p ./tsconfig.json -t 1000000 ./tests/test.ts" + } +} +``` + +### Початок Роботи + +Функція `start` з бібліотеки `solana-bankrun` запускає `BanksServer` і +`BanksClient`, розгортає програми та додає акаунти відповідно до ваших +інструкцій. + +Приклад використання: + +```typescript +import { start } from "solana-bankrun"; +import { PublicKey } from "@solana/web3.js"; + +test("testing program instruction", async () => { + const programId = PublicKey.unique(); + const context = await start([{ name: "program_name", programId }], []); + + const client = context.banksClient; + const payer = context.payer; + // write tests +}); +``` + +### `context` у Bankrun + +- Ми отримуємо доступ до `context` з функції `start`. `context` містить + `BanksClient`, останній blockhash та профінансовану keypair для підпису + транзакцій. +- У `context` є `payer`, який є профінансованою парою ключів і може + використовуватися для підпису транзакцій. +- `context` також містить `context.lastBlockhash` або + `context.getLatestBlockhash`, що спрощує отримання + [Blockhash](https://solana.com/docs/terminology#blockhash) під час тестів. +- `context.banksClient` використовується для надсилання транзакцій і отримання + даних акаунтів зі стану реєстру. Наприклад, іноді потрібна + [оренда (Rent)](https://solana.com/docs/terminology#rent) (в лампортах) для + створення транзакції, наприклад, при використанні інструкції `createAccount()` + з `SystemProgram`. Це можна зробити за допомогою `BanksClient`: + + ```typescript + const rent = await client.getRent(); + + const Ix: TransactionInstruction = SystemProgram.createAccount({ + // ... + lamports: Number(rent.minimumBalance(BigInt(ACCOUNT_SIZE))), + //.... + }); + ``` + +- Ви можете зчитувати дані акаунта з `BanksClient`, використовуючи функцію + `getAccount`. + + ```typescript + AccountInfo = await client.getAccount(counter); + ``` + +### Обробка Транзакції + +Функція `processTransaction()` виконує транзакцію з використанням завантажених +програм і акаунтів, отриманих із функції `start`. Вона повертає результат +виконаної транзакції. + +```typescript +let transaction = await client.processTransaction(tx); +``` + +## Приклад + +Ось приклад тесту для програми +[hello world](https://github.com/solana-developers/program-examples/tree/main/basics/hello-solana/native): + +```typescript +import { + PublicKey, + Transaction, + TransactionInstruction, +} from "@solana/web3.js"; +import { start } from "solana-bankrun"; +import { describe, test } from "node:test"; +import { assert } from "chai"; + +describe("hello-solana", async () => { + // load program in solana-bankrun + const PROGRAM_ID = PublicKey.unique(); + const context = await start( + [{ name: "hello_solana_program", programId: PROGRAM_ID }], + [], + ); + const client = context.banksClient; + const payer = context.payer; + + test("Say hello!", async () => { + const blockhash = context.lastBlockhash; + // We set up our instruction first. + let ix = new TransactionInstruction({ + // using payer keypair from context to sign the txn + keys: [{ pubkey: payer.publicKey, isSigner: true, isWritable: true }], + programId: PROGRAM_ID, + data: Buffer.alloc(0), // No data + }); + + const tx = new Transaction(); + tx.recentBlockhash = blockhash; + // using payer keypair from context to sign the txn + tx.add(ix).sign(payer); + + // Now we process the transaction + let transaction = await client.processTransaction(tx); + + assert(transaction.logMessages[0].startsWith("Program " + PROGRAM_ID)); + assert(transaction.logMessages[1] === "Program log: Hello, Solana!"); + assert( + transaction.logMessages[2] === + "Program log: Our program's Program ID: " + PROGRAM_ID, + ); + assert( + transaction.logMessages[3].startsWith( + "Program " + PROGRAM_ID + " consumed", + ), + ); + assert(transaction.logMessages[4] === "Program " + PROGRAM_ID + " success"); + assert(transaction.logMessages.length == 5); + }); +}); +``` + +Ось як виглядає результат після запуску тестів для +[hello world програми](https://github.com/solana-developers/program-examples/tree/main/basics/hello-solana/native): + +```text +[2024-06-04T12:57:36.188822000Z INFO solana_program_test] "hello_solana_program" SBF program from tests/fixtures/hello_solana_program.so, modified 3 seconds, 20 ms, 687 µs and 246 ns ago +[2024-06-04T12:57:36.246838000Z DEBUG solana_runtime::message_processor::stable_log] Program 11111111111111111111111111111112 invoke [1] +[2024-06-04T12:57:36.246892000Z DEBUG solana_runtime::message_processor::stable_log] Program log: Hello, Solana! +[2024-06-04T12:57:36.246917000Z DEBUG solana_runtime::message_processor::stable_log] Program log: Our program's Program ID: 11111111111111111111111111111112 +[2024-06-04T12:57:36.246932000Z DEBUG solana_runtime::message_processor::stable_log] Program 11111111111111111111111111111112 consumed 2905 of 200000 compute units +[2024-06-04T12:57:36.246937000Z DEBUG solana_runtime::message_processor::stable_log] Program 11111111111111111111111111111112 success +▶ hello-solana + ✔ Say hello! (5.667917ms) +▶ hello-solana (7.047667ms) + +ℹ tests 1 +ℹ suites 1 +ℹ pass 1 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 63.52616 +``` diff --git a/docs/locales/uk/rpc.md b/docs/locales/uk/rpc.md new file mode 100644 index 000000000..d63508930 --- /dev/null +++ b/docs/locales/uk/rpc.md @@ -0,0 +1,10 @@ +--- +title: Методи JSON RPC +sidebarSortOrder: 1 +isSkippedInNav: true +--- + +Цей файл не повинен редагуватися, оскільки він не призначений для відображення. +Він існує лише для створення посилання в головній бічній панелі документації. + +Документація JSON RPC для Solana доступна в [`rpc` каталозі](./rpc/) diff --git a/docs/locales/uk/rpc/deprecated/confirmTransaction.mdx b/docs/locales/uk/rpc/deprecated/confirmTransaction.mdx new file mode 100644 index 000000000..9ca5913b0 --- /dev/null +++ b/docs/locales/uk/rpc/deprecated/confirmTransaction.mdx @@ -0,0 +1,13 @@ +--- +sidebarLabel: confirmTransaction +title: confirmTransaction RPC Method +hideTableOfContents: true +--- + +Fetch the current status of a transaction signature (processed, confirmed, +finalized). + + + This method is expected to be removed in `solana-core` v2.0. Please use + [getSignatureStatuses](/docs/rpc/http/getSignatureStatuses) instead. + diff --git a/docs/locales/uk/rpc/deprecated/getConfirmedBlock.mdx b/docs/locales/uk/rpc/deprecated/getConfirmedBlock.mdx new file mode 100644 index 000000000..d9236f130 --- /dev/null +++ b/docs/locales/uk/rpc/deprecated/getConfirmedBlock.mdx @@ -0,0 +1,202 @@ +--- +sidebarLabel: getConfirmedBlock +title: getConfirmedBlock RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getConfirmedBlock + - /docs/rpc/http/getConfirmedBlock +--- + +Returns identity and transaction information about a confirmed block in the +ledger + + + This method is expected to be removed in `solana-core` v2.0. Please use + [getBlock](/docs/rpc/http/getBlock) instead. + + + + + + +### Parameters + + + slot number, as u64 integer + + + + +Configuration object containing the following fields: + + + + + level of transaction detail to return, either "full", "signatures", or "none" + + + + whether to populate the `rewards` array. + + + + +Encoding format for Account data + + + +
+ +- `jsonParsed` encoding attempts to use program-specific instruction parsers to + return more human-readable and explicit data in the + `transaction.message.instructions` list. +- If `jsonParsed` is requested but a parser cannot be found, the instruction + falls back to regular JSON encoding (`accounts`, `data`, and `programIdIndex` + fields). + +
+ +
+ +
+ +### Result + +The result field will be an object with the following fields: + +- `` - if specified block is not confirmed +- `` - if block is confirmed, an object with the following fields: + - `blockhash: ` - the blockhash of this block, as base-58 encoded + string + - `previousBlockhash: ` - the blockhash of this block's parent, as + base-58 encoded string; if the parent block is not available due to ledger + cleanup, this field will return "11111111111111111111111111111111" + - `parentSlot: ` - the slot index of this block's parent + - `transactions: ` - present if "full" transaction details are + requested; an array of JSON objects containing: + - `transaction: ` - + [Transaction](/docs/rpc/json-structures#transactions) object, either in + JSON format or encoded binary data, depending on encoding parameter + - `meta: ` - transaction status metadata object, containing `null` + or: + - `err: ` - Error if transaction failed, null if transaction + succeeded. + [TransactionError definitions](https://github.com/solana-labs/solana/blob/c0c60386544ec9a9ec7119229f37386d9f070523/sdk/src/transaction/error.rs#L13) + - `fee: ` - fee this transaction was charged, as u64 integer + - `preBalances: ` - array of u64 account balances from before the + transaction was processed + - `postBalances: ` - array of u64 account balances after the + transaction was processed + - `innerInstructions: ` - List of + [inner instructions](/docs/rpc/json-structures#inner-instructions) or + `null` if inner instruction recording was not enabled during this + transaction + - `preTokenBalances: ` - List of + [token balances](/docs/rpc/json-structures#token-balances) from before + the transaction was processed or omitted if token balance recording was + not yet enabled during this transaction + - `postTokenBalances: ` - List of + [token balances](/docs/rpc/json-structures#token-balances) from after + the transaction was processed or omitted if token balance recording was + not yet enabled during this transaction + - `logMessages: ` - array of string log messages or `null` if + log message recording was not enabled during this transaction + - DEPRECATED: `status: ` - Transaction status + - `"Ok": ` - Transaction was successful + - `"Err": ` - Transaction failed with TransactionError + - `signatures: ` - present if "signatures" are requested for + transaction details; an array of signatures strings, corresponding to the + transaction order in the block + - `rewards: ` - present if rewards are requested; an array of JSON + objects containing: + - `pubkey: ` - The public key, as base-58 encoded string, of the + account that received the reward + - `lamports: `- number of reward lamports credited or debited by the + account, as a i64 + - `postBalance: ` - account balance in lamports after the reward was + applied + - `rewardType: ` - type of reward: "fee", "rent", + "voting", "staking" + - `commission: ` - vote account commission when the reward was + credited, only present for voting and staking rewards + - `blockTime: ` - estimated production time, as Unix timestamp + (seconds since the Unix epoch). null if not available + +#### For more details on returned data: + +- [Transaction Structure](/docs/rpc/json-structures#transactions) +- [Inner Instructions Structure](/docs/rpc/json-structures#inner-instructions) +- [Token Balances Structure](/docs/rpc/json-structures#token-balances) + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", "id": 1, + "method": "getConfirmedBlock", + "params": [430, "base64"] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "blockTime": null, + "blockhash": "3Eq21vXNB5s86c62bVuUfTeaMif1N2kUqRPBmGRJhyTA", + "parentSlot": 429, + "previousBlockhash": "mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B", + "rewards": [], + "transactions": [ + { + "meta": { + "err": null, + "fee": 5000, + "innerInstructions": [], + "logMessages": [], + "postBalances": [499998932500, 26858640, 1, 1, 1], + "postTokenBalances": [], + "preBalances": [499998937500, 26858640, 1, 1, 1], + "preTokenBalances": [], + "status": { + "Ok": null + } + }, + "transaction": [ + "AVj7dxHlQ9IrvdYVIjuiRFs1jLaDMHixgrv+qtHBwz51L4/ImLZhszwiyEJDIp7xeBSpm/TX5B7mYzxa+fPOMw0BAAMFJMJVqLw+hJYheizSoYlLm53KzgT82cDVmazarqQKG2GQsLgiqktA+a+FDR4/7xnDX7rsusMwryYVUdixfz1B1Qan1RcZLwqvxvJl4/t3zHragsUp0L47E24tAFUgAAAABqfVFxjHdMkoVmOYaR1etoteuKObS21cc1VbIQAAAAAHYUgdNXR0u3xNdiTr072z2DVec9EQQ/wNo1OAAAAAAAtxOUhPBp2WSjUNJEgfvy70BbxI00fZyEPvFHNfxrtEAQQEAQIDADUCAAAAAQAAAAAAAACtAQAAAAAAAAdUE18R96XTJCe+YfRfUp6WP+YKCy/72ucOL8AoBFSpAA==", + "base64" + ] + } + ] + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/deprecated/getConfirmedBlocks.mdx b/docs/locales/uk/rpc/deprecated/getConfirmedBlocks.mdx new file mode 100644 index 000000000..2e4cc769b --- /dev/null +++ b/docs/locales/uk/rpc/deprecated/getConfirmedBlocks.mdx @@ -0,0 +1,65 @@ +--- +sidebarLabel: getConfirmedBlocks +title: getConfirmedBlocks RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getConfirmedBlocks + - /docs/rpc/http/getConfirmedBlocks +--- + +Returns a list of confirmed blocks between two slots + + + This method is expected to be removed in `solana-core` v2.0. Please use + [getBlocks](/docs/rpc/http/getblocks) instead. + + + + + + +### Parameters + + + start_slot, as u64 integer + + + + +Configuration object containing the following fields: + + + + + +### Result + +The result field will be an array of u64 integers listing confirmed blocks +between `start_slot` and either `end_slot` - if provided, or latest confirmed +block, inclusive. Max range allowed is 500,000 slots. + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc": "2.0","id":1,"method":"getConfirmedBlocks","params":[5, 10]} +' +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": [5, 6, 7, 8, 9, 10], "id": 1 } +``` + + + diff --git a/docs/locales/uk/rpc/deprecated/getConfirmedBlocksWithLimit.mdx b/docs/locales/uk/rpc/deprecated/getConfirmedBlocksWithLimit.mdx new file mode 100644 index 000000000..21efd752f --- /dev/null +++ b/docs/locales/uk/rpc/deprecated/getConfirmedBlocksWithLimit.mdx @@ -0,0 +1,72 @@ +--- +sidebarLabel: getConfirmedBlocksWithLimit +title: getConfirmedBlocksWithLimit RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getConfirmedBlocksWithLimit + - /docs/rpc/http/getConfirmedBlocksWithLimit +--- + +Returns a list of confirmed blocks starting at the given slot + + + This method is expected to be removed in `solana-core` v2.0. Please use + [getBlocksWithLimit](/docs/rpc/http/getblockswithlimit) instead. + + + + + + +### Parameters + + + start_slot, as u64 integer + + + + limit, as u64 integer + + + + +Configuration object containing the following fields: + + + + + +### Result + +The result field will be an array of u64 integers listing confirmed blocks +starting at `start_slot` for up to `limit` blocks, inclusive. + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", "id": 1, + "method": "getConfirmedBlocksWithLimit", + "params": [5, 3] + } +' +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": [5, 6, 7], "id": 1 } +``` + + + diff --git a/docs/locales/uk/rpc/deprecated/getConfirmedSignaturesForAddress2.mdx b/docs/locales/uk/rpc/deprecated/getConfirmedSignaturesForAddress2.mdx new file mode 100644 index 000000000..5db4d57a0 --- /dev/null +++ b/docs/locales/uk/rpc/deprecated/getConfirmedSignaturesForAddress2.mdx @@ -0,0 +1,120 @@ +--- +sidebarLabel: getConfirmedSignaturesForAddress2 +title: getConfirmedSignaturesForAddress2 RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getConfirmedSignaturesForAddress2 + - /docs/rpc/http/getConfirmedSignaturesForAddress2 + - /docs/rpc/getSignaturesForAddress2 + - /docs/rpc/http/getSignaturesForAddress2 + - /docs/rpc/deprecated/getSignaturesForAddress2 + - /docs/rpc/http/getconfirmedsignaturesforaddress + - /docs/rpc/deprecated/getconfirmedsignaturesforaddress + - /docs/rpc/getconfirmedsignaturesforaddress +--- + +Returns signatures for confirmed transactions that include the given address in +their `accountKeys` list. Returns signatures backwards in time from the provided +signature or most recent confirmed block + + + This method is expected to be removed in `solana-core` v2.0. Please use + [getSignaturesForAddress](/docs/rpc/http/getSignaturesForAddress) instead. + + + + + + +### Parameters + + + account address, as base-58 encoded string + + + +Configuration object containing the following fields: + + + + + maximum transaction signatures to return (between 1 and 1,000, default: + 1,000). + + + + start searching backwards from this transaction signature. (If not provided + the search starts from the top of the highest max confirmed block.) + + + + search until this transaction signature, if found before limit reached. + + + + +### Result + +The result field will be an array of ``, ordered from newest to oldest +transaction, containing transaction signature information with the following +fields: + +- `signature: ` - transaction signature as base-58 encoded string +- `slot: ` - The slot that contains the block with the transaction +- `err: ` - Error if transaction failed, null if transaction + succeeded. + [TransactionError definitions](https://github.com/solana-labs/solana/blob/c0c60386544ec9a9ec7119229f37386d9f070523/sdk/src/transaction/error.rs#L13) +- `memo: ` - Memo associated with the transaction, null if no memo + is present +- `blockTime: ` - estimated production time, as Unix timestamp + (seconds since the Unix epoch) of when transaction was processed. null if not + available. + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getConfirmedSignaturesForAddress2", + "params": [ + "Vote111111111111111111111111111111111111111", + { + "limit": 1 + } + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": [ + { + "err": null, + "memo": null, + "signature": "5h6xBEauJ3PK6SWCZ1PGjBvj8vDdWG3KpwATGy1ARAXFSDwt8GFXM7W5Ncn16wmqokgpiKRLuS83KUxyZyv2sUYv", + "slot": 114, + "blockTime": null + } + ], + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/deprecated/getConfirmedTransaction.mdx b/docs/locales/uk/rpc/deprecated/getConfirmedTransaction.mdx new file mode 100644 index 000000000..3a96d97c3 --- /dev/null +++ b/docs/locales/uk/rpc/deprecated/getConfirmedTransaction.mdx @@ -0,0 +1,153 @@ +--- +sidebarLabel: getConfirmedTransaction +title: getConfirmedTransaction RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getConfirmedTransaction + - /docs/rpc/http/getConfirmedTransaction +--- + +Returns transaction details for a confirmed transaction + + + This method is expected to be removed in `solana-core` v2.0. Please use + [getTransaction](/docs/rpc/http/getTransaction) instead. + + + + + + +### Parameters + + + transaction signature, as base-58 encoded string + + + + +Configuration object containing the following fields: + + + + + +Encoding format for Account data + + + +
+ +- `base58` is slow and limited to less than 129 bytes of Account data. +- `jsonParsed` encoding attempts to use program-specific instruction parsers to + return more human-readable and explicit data in the + `transaction.message.instructions` list. +- If `jsonParsed` is requested but a parser cannot be found, the instruction + falls back to regular `json` encoding (`accounts`, `data`, and + `programIdIndex` fields). + +
+ +
+ +
+ +### Result + +- `` - if transaction is not found or not confirmed +- `` - if transaction is confirmed, an object with the following fields: + - `slot: ` - the slot this transaction was processed in + - `transaction: ` - + [Transaction](/docs/rpc/json-structures#transactions) object, either in JSON + format or encoded binary data, depending on encoding parameter + - `blockTime: ` - estimated production time, as Unix timestamp + (seconds since the Unix epoch) of when the transaction was processed. null + if not available + - `meta: ` - transaction status metadata object: + - `err: ` - Error if transaction failed, null if transaction + succeeded. + [TransactionError definitions](https://docs.rs/solana-sdk/latest/solana_sdk/transaction/enum.TransactionError.html) + - `fee: ` - fee this transaction was charged, as u64 integer + - `preBalances: ` - array of u64 account balances from before the + transaction was processed + - `postBalances: ` - array of u64 account balances after the + transaction was processed + - `innerInstructions: ` - List of + [inner instructions](/docs/rpc/json-structures#inner-instructions) or + `null` if inner instruction recording was not enabled during this + transaction + - `preTokenBalances: ` - List of + [token balances](/docs/rpc/json-structures#token-balances) from before the + transaction was processed or omitted if token balance recording was not + yet enabled during this transaction + - `postTokenBalances: ` - List of + [token balances](/docs/rpc/json-structures#token-balances) from after the + transaction was processed or omitted if token balance recording was not + yet enabled during this transaction + - `logMessages: ` - array of string log messages or `null` if + log message recording was not enabled during this transaction + - DEPRECATED: `status: ` - Transaction status + - `"Ok": ` - Transaction was successful + - `"Err": ` - Transaction failed with TransactionError + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getConfirmedTransaction", + "params": [ + "2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv", + "base64" + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "meta": { + "err": null, + "fee": 5000, + "innerInstructions": [], + "postBalances": [499998932500, 26858640, 1, 1, 1], + "postTokenBalances": [], + "preBalances": [499998937500, 26858640, 1, 1, 1], + "preTokenBalances": [], + "status": { + "Ok": null + } + }, + "slot": 430, + "transaction": [ + "AVj7dxHlQ9IrvdYVIjuiRFs1jLaDMHixgrv+qtHBwz51L4/ImLZhszwiyEJDIp7xeBSpm/TX5B7mYzxa+fPOMw0BAAMFJMJVqLw+hJYheizSoYlLm53KzgT82cDVmazarqQKG2GQsLgiqktA+a+FDR4/7xnDX7rsusMwryYVUdixfz1B1Qan1RcZLwqvxvJl4/t3zHragsUp0L47E24tAFUgAAAABqfVFxjHdMkoVmOYaR1etoteuKObS21cc1VbIQAAAAAHYUgdNXR0u3xNdiTr072z2DVec9EQQ/wNo1OAAAAAAAtxOUhPBp2WSjUNJEgfvy70BbxI00fZyEPvFHNfxrtEAQQEAQIDADUCAAAAAQAAAAAAAACtAQAAAAAAAAdUE18R96XTJCe+YfRfUp6WP+YKCy/72ucOL8AoBFSpAA==", + "base64" + ] + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/deprecated/getFeeCalculatorForBlockhash.mdx b/docs/locales/uk/rpc/deprecated/getFeeCalculatorForBlockhash.mdx new file mode 100644 index 000000000..75d6093e0 --- /dev/null +++ b/docs/locales/uk/rpc/deprecated/getFeeCalculatorForBlockhash.mdx @@ -0,0 +1,94 @@ +--- +sidebarLabel: getFeeCalculatorForBlockhash +title: getFeeCalculatorForBlockhash RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getFeeCalculatorForBlockhash + - /docs/rpc/http/getFeeCalculatorForBlockhash +--- + +Returns the fee calculator associated with the query blockhash, or `null` if the +blockhash has expired + + + This method is expected to be removed in `solana-core` v2.0. Please use + [isBlockhashValid](/docs/rpc/http/isBlockhashValid) or + [getFeeForMessage](/docs/rpc/http/getFeeForMessage) instead. + + + + + + +### Parameters + + + query blockhash, as a base-58 encoded string + + + + +Configuration object containing the following fields: + + + + + The minimum slot that the request can be evaluated at + + + + +### Result + +The result will be an RpcResponse JSON object with `value` equal to: + +- `` - if the query blockhash has expired; or +- `` - otherwise, a JSON object containing: + - `feeCalculator: ` - `FeeCalculator` object describing the cluster + fee rate at the queried blockhash + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getFeeCalculatorForBlockhash", + "params": [ + "GJxqhuxcgfn5Tcj6y3f8X4FeCDd2RQ6SnEMo1AAxrPRZ" + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 221 + }, + "value": { + "feeCalculator": { + "lamportsPerSignature": 5000 + } + } + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/deprecated/getFeeRateGovernor.mdx b/docs/locales/uk/rpc/deprecated/getFeeRateGovernor.mdx new file mode 100644 index 000000000..292be480e --- /dev/null +++ b/docs/locales/uk/rpc/deprecated/getFeeRateGovernor.mdx @@ -0,0 +1,74 @@ +--- +sidebarLabel: getFeeRateGovernor +title: getFeeRateGovernor RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getFeeRateGovernor + - /docs/rpc/http/getFeeRateGovernor +--- + +Returns the fee rate governor information from the root bank + + + This method is expected to be removed in `solana-core` v2.0. Please use + [getFeeForMessage](/docs/rpc/http/getFeeForMessage) instead. + + + + + + +### Parameters + +**None** + +### Result + +The result will be an RpcResponse JSON object with `value` equal to an `object` +with the following fields: + +- `burnPercent: ` - Percentage of fees collected to be destroyed +- `maxLamportsPerSignature: ` - Largest value `lamportsPerSignature` can + attain for the next slot +- `minLamportsPerSignature: ` - Smallest value `lamportsPerSignature` can + attain for the next slot +- `targetLamportsPerSignature: ` - Desired fee rate for the cluster +- `targetSignaturesPerSlot: ` - Desired signature rate for the cluster + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getFeeRateGovernor"} +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 54 + }, + "value": { + "feeRateGovernor": { + "burnPercent": 50, + "maxLamportsPerSignature": 100000, + "minLamportsPerSignature": 5000, + "targetLamportsPerSignature": 10000, + "targetSignaturesPerSlot": 20000 + } + } + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/deprecated/getFees.mdx b/docs/locales/uk/rpc/deprecated/getFees.mdx new file mode 100644 index 000000000..30f0a2435 --- /dev/null +++ b/docs/locales/uk/rpc/deprecated/getFees.mdx @@ -0,0 +1,91 @@ +--- +sidebarLabel: getFees +title: getFees RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getFees + - /docs/rpc/http/getFees +--- + +Returns a recent block hash from the ledger, a fee schedule that can be used to +compute the cost of submitting a transaction using it, and the last slot in +which the blockhash will be valid. + + + This method is expected to be removed in `solana-core` v2.0. Please use + [getFeeForMessage](/docs/rpc/http/getFeeForMessage) instead. + + + + + + +### Parameters + + + Pubkey of account to query, as base-58 encoded string + + + + +Configuration object containing the following fields: + + + + + +### Result + +The result will be an RpcResponse JSON object with `value` set to a JSON object +with the following fields: + +- `blockhash: ` - a Hash as base-58 encoded string +- `feeCalculator: ` - FeeCalculator object, the fee schedule for this + block hash +- `lastValidSlot: ` - DEPRECATED - this value is inaccurate and should not + be relied upon +- `lastValidBlockHeight: ` - last + [block height](/docs/terminology.md#block-height) at which the blockhash will + be valid + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { "jsonrpc":"2.0", "id": 1, "method":"getFees"} +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 1 + }, + "value": { + "blockhash": "CSymwgTNX1j3E4qhKfJAUE41nBWEwXufoYryPbkde5RR", + "feeCalculator": { + "lamportsPerSignature": 5000 + }, + "lastValidSlot": 297, + "lastValidBlockHeight": 296 + } + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/deprecated/getRecentBlockhash.mdx b/docs/locales/uk/rpc/deprecated/getRecentBlockhash.mdx new file mode 100644 index 000000000..5668aa90a --- /dev/null +++ b/docs/locales/uk/rpc/deprecated/getRecentBlockhash.mdx @@ -0,0 +1,85 @@ +--- +sidebarLabel: getRecentBlockhash +title: getRecentBlockhash RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/http/getRecentBlockhash + - /docs/rpc/getRecentBlockhash +--- + +Returns a recent block hash from the ledger, and a fee schedule that can be used +to compute the cost of submitting a transaction using it. + + + This method is expected to be removed in `solana-core` v2.0. Please use + [getLatestBlockhash](/docs/rpc/http/getlatestblockhash) instead. + + + + + + +### Parameters + + + Pubkey of account to query, as base-58 encoded string + + + + +Configuration object containing the following fields: + + + + + +### Result + +An RpcResponse containing a JSON object consisting of a string blockhash and +FeeCalculator JSON object. + +- `RpcResponse` - RpcResponse JSON object with `value` field set to a + JSON object including: +- `blockhash: ` - a Hash as base-58 encoded string +- `feeCalculator: ` - FeeCalculator object, the fee schedule for this + block hash + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getRecentBlockhash"} +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 1 + }, + "value": { + "blockhash": "CSymwgTNX1j3E4qhKfJAUE41nBWEwXufoYryPbkde5RR", + "feeCalculator": { + "lamportsPerSignature": 5000 + } + } + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/deprecated/getSignatureConfirmation.mdx b/docs/locales/uk/rpc/deprecated/getSignatureConfirmation.mdx new file mode 100644 index 000000000..6bdda7caf --- /dev/null +++ b/docs/locales/uk/rpc/deprecated/getSignatureConfirmation.mdx @@ -0,0 +1,13 @@ +--- +sidebarLabel: getSignatureConfirmation +title: getSignatureConfirmation RPC Method +hideTableOfContents: true +--- + +Fetch the current status of a transaction signature (processed, confirmed, +finalized). + + + This method is expected to be removed in `solana-core` v2.0. Please use + [getSignatureStatuses](/docs/rpc/http/getSignatureStatuses) instead. + diff --git a/docs/locales/uk/rpc/deprecated/getSignatureStatus.mdx b/docs/locales/uk/rpc/deprecated/getSignatureStatus.mdx new file mode 100644 index 000000000..fa6211755 --- /dev/null +++ b/docs/locales/uk/rpc/deprecated/getSignatureStatus.mdx @@ -0,0 +1,13 @@ +--- +sidebarLabel: getSignatureStatus +title: getSignatureStatus RPC Method +hideTableOfContents: true +--- + +Fetch the current status of a transaction signature (processed, confirmed, +finalized). + + + This method is expected to be removed in `solana-core` v2.0. Please use + [getSignatureStatuses](/docs/rpc/http/getSignatureStatuses) instead. + diff --git a/docs/locales/uk/rpc/deprecated/getSnapshotSlot.mdx b/docs/locales/uk/rpc/deprecated/getSnapshotSlot.mdx new file mode 100644 index 000000000..6b4d83fc7 --- /dev/null +++ b/docs/locales/uk/rpc/deprecated/getSnapshotSlot.mdx @@ -0,0 +1,58 @@ +--- +sidebarLabel: getSnapshotSlot +title: getSnapshotSlot RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/http/getSnapshotSlot + - /docs/rpc/getSnapshotSlot +--- + +Returns the highest slot that the node has a snapshot for + + + This method is expected to be removed in `solana-core` v2.0. Please use + [getHighestSnapshotSlot](/docs/rpc/http/getHighestSnapshotSlot) instead. + + + + + + +### Parameters + +**None** + +### Result + +`` - Snapshot slot + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getSnapshotSlot"} +' +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": 100, "id": 1 } +``` + +Result when the node has no snapshot: + +```json +{ + "jsonrpc": "2.0", + "error": { "code": -32008, "message": "No snapshot" }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/deprecated/getStakeActivation.mdx b/docs/locales/uk/rpc/deprecated/getStakeActivation.mdx new file mode 100644 index 000000000..c0a808703 --- /dev/null +++ b/docs/locales/uk/rpc/deprecated/getStakeActivation.mdx @@ -0,0 +1,97 @@ +--- +sidebarLabel: getStakeActivation +title: getStakeActivation RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/http/getStakeActivation +--- + +Returns epoch activation information for a stake account + + + This method is expected to be removed in `solana-core` v2.0. Please use [this + alternative + approach](https://github.com/solana-developers/solana-rpc-get-stake-activation) + instead. + + + + + + +### Parameters + + + Pubkey of stake Account to query, as base-58 encoded string + + + + +Configuration object containing the following fields: + + + + + The minimum slot that the request can be evaluated at + + + + epoch for which to calculate activation details. If parameter not provided, + defaults to current epoch. **DEPRECATED**, inputs other than the current epoch + return an error. + + + + +### Result + +The result will be a JSON object with the following fields: + +- `state: ` - the stake account's activation state, either: `active`, + `inactive`, `activating`, or `deactivating` +- `active: ` - stake active during the epoch +- `inactive: ` - stake inactive during the epoch + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getStakeActivation", + "params": [ + "CYRJWqiSjLitBAcRxPvWpgX3s5TvmN2SuRY3eEYypFvT", + { + "epoch": 4 + } + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "active": 124429280, + "inactive": 73287840, + "state": "activating" + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/deprecated/index.mdx b/docs/locales/uk/rpc/deprecated/index.mdx new file mode 100644 index 000000000..45ee991ad --- /dev/null +++ b/docs/locales/uk/rpc/deprecated/index.mdx @@ -0,0 +1,6 @@ +--- +title: Deprecated Methods +sidebarSortOrder: 9999 +hideTableOfContents: true +metaOnly: true +--- diff --git a/docs/locales/uk/rpc/http/getAccountInfo.mdx b/docs/locales/uk/rpc/http/getAccountInfo.mdx new file mode 100644 index 000000000..a96d9ebb2 --- /dev/null +++ b/docs/locales/uk/rpc/http/getAccountInfo.mdx @@ -0,0 +1,138 @@ +--- +sidebarLabel: getAccountInfo +title: getAccountInfo RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getAccountInfo +--- + +Returns all information associated with the account of provided Pubkey + + + + + +### Parameters + + + Pubkey of account to query, as base-58 encoded string + + + + +Configuration object containing the following fields: + + + + + +Encoding format for Account data + + + +
+ +- `base58` is slow and limited to less than 129 bytes of Account data. +- `base64` will return base64 encoded data for Account data of any size. +- `base64+zstd` compresses the Account data using + [Zstandard](https://facebook.github.io/zstd/) and base64-encodes the result. +- `jsonParsed` encoding attempts to use program-specific state parsers to return + more human-readable and explicit account state data. +- If `jsonParsed` is requested but a parser cannot be found, the field falls + back to `base64` encoding, detectable when the `data` field is type `string`. + +
+ +
+ + + Request a slice of the account's data. + +- `length: ` - number of bytes to return +- `offset: ` - byte offset from which to start reading + + + Data slicing is only available for `base58`, `base64`, or `base64+zstd` + encodings. + + + + + + The minimum slot that the request can be evaluated at + + +
+ +### Result + +The result will be an RpcResponse JSON object with `value` equal to: + +- `` - if the requested account doesn't exist +- `` - otherwise, a JSON object containing: + - `lamports: ` - number of lamports assigned to this account, as a u64 + - `owner: ` - base-58 encoded Pubkey of the program this account has + been assigned to + - `data: <[string, encoding]|object>` - data associated with the account, + either as encoded binary data or JSON format `{: }` - + depending on encoding parameter + - `executable: ` - boolean indicating if the account contains a program + \(and is strictly read-only\) + - `rentEpoch: ` - the epoch at which this account will next owe rent, as + u64 + - `space: ` - the data size of the account + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getAccountInfo", + "params": [ + "vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg", + { + "encoding": "base58" + } + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { "apiVersion": "2.0.15", "slot": 341197053 }, + "value": { + "data": ["", "base58"], + "executable": false, + "lamports": 88849814690250, + "owner": "11111111111111111111111111111111", + "rentEpoch": 18446744073709551615, + "space": 0 + } + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getBalance.mdx b/docs/locales/uk/rpc/http/getBalance.mdx new file mode 100644 index 000000000..514f653cf --- /dev/null +++ b/docs/locales/uk/rpc/http/getBalance.mdx @@ -0,0 +1,72 @@ +--- +sidebarLabel: getBalance +title: getBalance RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getBalance +--- + +Returns the lamport balance of the account of provided Pubkey + + + + + +### Parameters + + + Pubkey of account to query, as base-58 encoded string + + + + +Configuration object containing the following fields: + + + + + The minimum slot that the request can be evaluated at + + + + +### Result + +`RpcResponse` - RpcResponse JSON object with `value` field set to the +balance + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", "id": 1, + "method": "getBalance", + "params": [ + "83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri" + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { "context": { "slot": 1 }, "value": 0 }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getBlock.mdx b/docs/locales/uk/rpc/http/getBlock.mdx new file mode 100644 index 000000000..d75329dc4 --- /dev/null +++ b/docs/locales/uk/rpc/http/getBlock.mdx @@ -0,0 +1,287 @@ +--- +sidebarLabel: getBlock +title: getBlock RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getBlock +--- + +Returns identity and transaction information about a confirmed block in the +ledger + + + + + +### Parameters + + + slot number, as `u64` integer + + + + +Configuration object containing the following fields: + + + +- `processed` is not supported. + + + + + +encoding format for each returned Transaction + + + +
+ +- `jsonParsed` attempts to use program-specific instruction parsers to return + more human-readable and explicit data in the + `transaction.message.instructions` list. +- If `jsonParsed` is requested but a parser cannot be found, the instruction + falls back to regular JSON encoding (`accounts`, `data`, and `programIdIndex` + fields). + +
+ +
+ + + +level of transaction detail to return + + + +
+ +- If `accounts` are requested, transaction details only include signatures and + an annotated list of accounts in each transaction. +- Transaction metadata is limited to only: fee, err, pre_balances, + post_balances, pre_token_balances, and post_token_balances. + +
+ +
+ + + +the max transaction version to return in responses. + +
+ +- If the requested block contains a transaction with a higher version, an error + will be returned. +- If this parameter is omitted, only legacy transactions will be returned, and a + block containing any versioned transaction will prompt the error. + +
+ +
+ + + whether to populate the `rewards` array. If parameter not provided, the + default includes rewards. + + +
+ +### Result + +The result field will be an object with the following fields: + +- `` - if specified block is not confirmed +- `` - if block is confirmed, an object with the following fields: + - `blockhash: ` - the blockhash of this block, as base-58 encoded + string + - `previousBlockhash: ` - the blockhash of this block's parent, as + base-58 encoded string; if the parent block is not available due to ledger + cleanup, this field will return "11111111111111111111111111111111" + - `parentSlot: ` - the slot index of this block's parent + - `transactions: ` - present if "full" transaction details are + requested; an array of JSON objects containing: + - `transaction: ` - + [Transaction](/docs/rpc/json-structures#transactions) object, either in + JSON format or encoded binary data, depending on encoding parameter + - `meta: ` - transaction status metadata object, containing `null` + or: + - `err: ` - Error if transaction failed, null if transaction + succeeded. + [TransactionError definitions](https://github.com/solana-labs/solana/blob/c0c60386544ec9a9ec7119229f37386d9f070523/sdk/src/transaction/error.rs#L13) + - `fee: ` - fee this transaction was charged, as u64 integer + - `preBalances: ` - array of u64 account balances from before the + transaction was processed + - `postBalances: ` - array of u64 account balances after the + transaction was processed + - `innerInstructions: ` - List of + [inner instructions](/docs/rpc/json-structures#inner-instructions) or + `null` if inner instruction recording was not enabled during this + transaction + - `preTokenBalances: ` - List of + [token balances](/docs/rpc/json-structures#token-balances) from before + the transaction was processed or omitted if token balance recording was + not yet enabled during this transaction + - `postTokenBalances: ` - List of + [token balances](/docs/rpc/json-structures#token-balances) from after + the transaction was processed or omitted if token balance recording was + not yet enabled during this transaction + - `logMessages: ` - array of string log messages or `null` if + log message recording was not enabled during this transaction + - `rewards: ` - transaction-level rewards, populated if + rewards are requested; an array of JSON objects containing: + - `pubkey: ` - The public key, as base-58 encoded string, of the + account that received the reward + - `lamports: `- number of reward lamports credited or debited by + the account, as a i64 + - `postBalance: ` - account balance in lamports after the reward + was applied + - `rewardType: ` - type of reward: "fee", "rent", + "voting", "staking" + - `commission: ` - vote account commission when the reward + was credited, only present for voting and staking rewards + - DEPRECATED: `status: ` - Transaction status + - `"Ok": ` - Transaction was successful + - `"Err": ` - Transaction failed with TransactionError + - `loadedAddresses: ` - Transaction addresses loaded + from address lookup tables. Undefined if + `maxSupportedTransactionVersion` is not set in request params, or if + `jsonParsed` encoding is set in request params. + - `writable: ` - Ordered list of base-58 encoded + addresses for writable loaded accounts + - `readonly: ` - Ordered list of base-58 encoded + addresses for readonly loaded accounts + - `returnData: ` - the most-recent return data generated + by an instruction in the transaction, with the following fields: + - `programId: ` - the program that generated the return data, as + base-58 encoded Pubkey + - `data: <[string, encoding]>` - the return data itself, as base-64 + encoded binary data + - `computeUnitsConsumed: ` - number of + [compute units](/docs/core/fees.md#compute-budget) consumed by the + transaction + - `version: <"legacy"|number|undefined>` - Transaction version. Undefined if + `maxSupportedTransactionVersion` is not set in request params. + - `signatures: ` - present if "signatures" are requested for + transaction details; an array of signatures strings, corresponding to the + transaction order in the block + - `rewards: ` - block-level rewards, present if rewards are + requested; an array of JSON objects containing: + - `pubkey: ` - The public key, as base-58 encoded string, of the + account that received the reward + - `lamports: `- number of reward lamports credited or debited by the + account, as a i64 + - `postBalance: ` - account balance in lamports after the reward was + applied + - `rewardType: ` - type of reward: "fee", "rent", + "voting", "staking" + - `commission: ` - vote account commission when the reward was + credited, only present for voting and staking rewards + - `blockTime: ` - estimated production time, as Unix timestamp + (seconds since the Unix epoch). null if not available + - `blockHeight: ` - the number of blocks beneath this block + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0","id":1, + "method":"getBlock", + "params": [ + 430, + { + "encoding": "json", + "maxSupportedTransactionVersion":0, + "transactionDetails":"full", + "rewards":false + } + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "blockHeight": 428, + "blockTime": null, + "blockhash": "3Eq21vXNB5s86c62bVuUfTeaMif1N2kUqRPBmGRJhyTA", + "parentSlot": 429, + "previousBlockhash": "mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B", + "transactions": [ + { + "meta": { + "err": null, + "fee": 5000, + "innerInstructions": [], + "logMessages": [], + "postBalances": [499998932500, 26858640, 1, 1, 1], + "postTokenBalances": [], + "preBalances": [499998937500, 26858640, 1, 1, 1], + "preTokenBalances": [], + "rewards": null, + "status": { + "Ok": null + } + }, + "transaction": { + "message": { + "accountKeys": [ + "3UVYmECPPMZSCqWKfENfuoTv51fTDTWicX9xmBD2euKe", + "AjozzgE83A3x1sHNUR64hfH7zaEBWeMaFuAN9kQgujrc", + "SysvarS1otHashes111111111111111111111111111", + "SysvarC1ock11111111111111111111111111111111", + "Vote111111111111111111111111111111111111111" + ], + "header": { + "numReadonlySignedAccounts": 0, + "numReadonlyUnsignedAccounts": 3, + "numRequiredSignatures": 1 + }, + "instructions": [ + { + "accounts": [1, 2, 3, 0], + "data": "37u9WtQpcm6ULa3WRQHmj49EPs4if7o9f1jSRVZpm2dvihR9C8jY4NqEwXUbLwx15HBSNcP1", + "programIdIndex": 4 + } + ], + "recentBlockhash": "mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B" + }, + "signatures": [ + "2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv" + ] + } + } + ] + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getBlockCommitment.mdx b/docs/locales/uk/rpc/http/getBlockCommitment.mdx new file mode 100644 index 000000000..3d4446da0 --- /dev/null +++ b/docs/locales/uk/rpc/http/getBlockCommitment.mdx @@ -0,0 +1,65 @@ +--- +sidebarLabel: getBlockCommitment +title: getBlockCommitment RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getBlockCommitment +--- + +Returns commitment for particular block + + + + + +### Parameters + + + block number, identified by Slot + + +### Result + +The result field will be a JSON object containing: + +- `commitment` - commitment, comprising either: + - `` - Unknown block + - `` - commitment, array of u64 integers logging the amount of cluster + stake in lamports that has voted on the block at each depth from 0 to + `MAX_LOCKOUT_HISTORY` + 1 +- `totalStake` - total active stake, in lamports, of the current epoch + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", "id": 1, + "method": "getBlockCommitment", + "params":[5] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "commitment": [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 10, 32 + ], + "totalStake": 42 + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getBlockHeight.mdx b/docs/locales/uk/rpc/http/getBlockHeight.mdx new file mode 100644 index 000000000..8be00d7b0 --- /dev/null +++ b/docs/locales/uk/rpc/http/getBlockHeight.mdx @@ -0,0 +1,66 @@ +--- +sidebarLabel: getBlockHeight +title: getBlockHeight RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getBlockHeight +--- + +Returns the current block height of the node + + + + + +### Parameters + + + +Configuration object containing the following fields: + + + + + The minimum slot that the request can be evaluated at + + + + +### Result + +- `` - Current block height + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc":"2.0","id":1, + "method":"getBlockHeight" + } +' +``` + +Result: + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": 1233, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getBlockProduction.mdx b/docs/locales/uk/rpc/http/getBlockProduction.mdx new file mode 100644 index 000000000..90d03b34f --- /dev/null +++ b/docs/locales/uk/rpc/http/getBlockProduction.mdx @@ -0,0 +1,94 @@ +--- +sidebarLabel: getBlockProduction +title: getBlockProduction RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getBlockProduction +--- + +Returns recent block production information from the current or previous epoch. + + + + + +### Parameters + + + +Configuration object containing the following fields: + + + + + Only return results for this validator identity (base-58 encoded) + + + +Slot range to return block production for. If parameter not provided, defaults to current epoch. + +- `firstSlot: ` - first slot to return block production information for + (inclusive) +- (optional) `lastSlot: ` - last slot to return block production + information for (inclusive). If parameter not provided, defaults to the + highest slot + + + + + +### Result + +The result will be an RpcResponse JSON object with `value` equal to: + +- `` + - `byIdentity: ` - a dictionary of validator identities, as base-58 + encoded strings. Value is a two element array containing the number of + leader slots and the number of blocks produced. + - `range: ` - Block production slot range + - `firstSlot: ` - first slot of the block production information + (inclusive) + - `lastSlot: ` - last slot of block production information (inclusive) + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getBlockProduction"} +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 9887 + }, + "value": { + "byIdentity": { + "85iYT5RuzRTDgjyRa3cP8SYhM2j21fj7NhfJ3peu1DPr": [9888, 9886] + }, + "range": { + "firstSlot": 0, + "lastSlot": 9887 + } + } + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getBlockTime.mdx b/docs/locales/uk/rpc/http/getBlockTime.mdx new file mode 100644 index 000000000..c0435fab4 --- /dev/null +++ b/docs/locales/uk/rpc/http/getBlockTime.mdx @@ -0,0 +1,75 @@ +--- +sidebarLabel: getBlockTime +title: getBlockTime RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getBlockTime +--- + +Returns the estimated production time of a block. + + + Each validator reports their UTC time to the ledger on a regular interval by + intermittently adding a timestamp to a Vote for a particular block. A + requested block's time is calculated from the stake-weighted mean of the Vote + timestamps in a set of recent blocks recorded on the ledger. + + + + + + +### Parameters + + + block number, identified by Slot + + +### Result + +- `` - estimated production time, as Unix timestamp (seconds since the Unix + epoch) + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc":"2.0", "id":1, + "method": "getBlockTime", + "params":[5] + } +' +``` + +### Response + +When a block time is available: + +```json +{ + "jsonrpc": "2.0", + "result": 1574721591, + "id": 1 +} +``` + +When a block time is not available: + +```json +{ + "jsonrpc": "2.0", + "error": { + "code": -32004, + "message": "Block not available for slot 150" + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getBlocks.mdx b/docs/locales/uk/rpc/http/getBlocks.mdx new file mode 100644 index 000000000..3967e2a85 --- /dev/null +++ b/docs/locales/uk/rpc/http/getBlocks.mdx @@ -0,0 +1,79 @@ +--- +sidebarLabel: getBlocks +title: getBlocks RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getBlocks +--- + +Returns a list of confirmed blocks between two slots + + + + + +### Parameters + + + start_slot, as `u64` integer + + + + end_slot, as `u64` integer (must be no more than 500,000 blocks higher than + the `start_slot`) + + + + +Configuration object containing the following fields: + + + +- "processed" is not supported + + + + + +### Result + +The result field will be an array of u64 integers listing confirmed blocks +between `start_slot` and either `end_slot` - if provided, or latest confirmed +block, inclusive. Max range allowed is 500,000 slots. + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", "id": 1, + "method": "getBlocks", + "params": [ + 5, 10 + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": [5, 6, 7, 8, 9, 10], + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getBlocksWithLimit.mdx b/docs/locales/uk/rpc/http/getBlocksWithLimit.mdx new file mode 100644 index 000000000..f86b888bc --- /dev/null +++ b/docs/locales/uk/rpc/http/getBlocksWithLimit.mdx @@ -0,0 +1,77 @@ +--- +sidebarLabel: getBlocksWithLimit +title: getBlocksWithLimit RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getBlocksWithLimit +--- + +Returns a list of confirmed blocks starting at the given slot + + + + + +### Parameters + + + start_slot, as `u64` integer + + + + limit, as `u64` integer (must be no more than 500,000 blocks higher than the + `start_slot`) + + + + +Configuration object containing the following field: + + + +- "processed" is not supported + + + + + +### Result + +The result field will be an array of u64 integers listing confirmed blocks +starting at `start_slot` for up to `limit` blocks, inclusive. + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id":1, + "method":"getBlocksWithLimit", + "params":[5, 3] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": [5, 6, 7], + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getClusterNodes.mdx b/docs/locales/uk/rpc/http/getClusterNodes.mdx new file mode 100644 index 000000000..18e685a75 --- /dev/null +++ b/docs/locales/uk/rpc/http/getClusterNodes.mdx @@ -0,0 +1,69 @@ +--- +sidebarLabel: getClusterNodes +title: getClusterNodes RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getClusterNodes +--- + +Returns information about all the nodes participating in the cluster + + + + + +### Parameters + +**None** + +### Result + +The result field will be an array of JSON objects, each with the following sub +fields: + +- `pubkey: ` - Node public key, as base-58 encoded string +- `gossip: ` - Gossip network address for the node +- `tpu: ` - TPU network address for the node +- `rpc: ` - JSON RPC network address for the node, or `null` if the + JSON RPC service is not enabled +- `version: ` - The software version of the node, or `null` if the + version information is not available +- `featureSet: ` - The unique identifier of the node's feature set +- `shredVersion: ` - The shred version the node has been configured to + use + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", "id": 1, + "method": "getClusterNodes" + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": [ + { + "gossip": "10.239.6.48:8001", + "pubkey": "9QzsJf7LPLj8GkXbYT3LFDKqsj2hHG7TA3xinJHu8epQ", + "rpc": "10.239.6.48:8899", + "tpu": "10.239.6.48:8856", + "version": "1.0.0 c375ce1f" + } + ], + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getEpochInfo.mdx b/docs/locales/uk/rpc/http/getEpochInfo.mdx new file mode 100644 index 000000000..ce4f696e6 --- /dev/null +++ b/docs/locales/uk/rpc/http/getEpochInfo.mdx @@ -0,0 +1,76 @@ +--- +sidebarLabel: getEpochInfo +title: getEpochInfo RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getEpochInfo +--- + +Returns information about the current epoch + + + + + +### Parameters + + + +Configuration object containing the following fields: + + + + + The minimum slot that the request can be evaluated at + + + + +### Result + +The result field will be an object with the following fields: + +- `absoluteSlot: ` - the current slot +- `blockHeight: ` - the current block height +- `epoch: ` - the current epoch +- `slotIndex: ` - the current slot relative to the start of the current + epoch +- `slotsInEpoch: ` - the number of slots in this epoch +- `transactionCount: ` - total number of transactions processed + without error since genesis + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getEpochInfo"} +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "absoluteSlot": 166598, + "blockHeight": 166500, + "epoch": 27, + "slotIndex": 2790, + "slotsInEpoch": 8192, + "transactionCount": 22661093 + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getEpochSchedule.mdx b/docs/locales/uk/rpc/http/getEpochSchedule.mdx new file mode 100644 index 000000000..46f61341f --- /dev/null +++ b/docs/locales/uk/rpc/http/getEpochSchedule.mdx @@ -0,0 +1,64 @@ +--- +sidebarLabel: getEpochSchedule +title: getEpochSchedule RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getEpochSchedule +--- + +Returns the epoch schedule information from this cluster's genesis config + + + + + +### Parameters + +**None** + +### Result + +The result field will be an object with the following fields: + +- `slotsPerEpoch: ` - the maximum number of slots in each epoch +- `leaderScheduleSlotOffset: ` - the number of slots before beginning of an + epoch to calculate a leader schedule for that epoch +- `warmup: ` - whether epochs start short and grow +- `firstNormalEpoch: ` - first normal-length epoch, log2(slotsPerEpoch) - + log2(MINIMUM_SLOTS_PER_EPOCH) +- `firstNormalSlot: ` - MINIMUM_SLOTS_PER_EPOCH \* + (2.pow(firstNormalEpoch) - 1) + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc":"2.0","id":1, + "method":"getEpochSchedule" + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "firstNormalEpoch": 8, + "firstNormalSlot": 8160, + "leaderScheduleSlotOffset": 8192, + "slotsPerEpoch": 8192, + "warmup": true + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getFeeForMessage.mdx b/docs/locales/uk/rpc/http/getFeeForMessage.mdx new file mode 100644 index 000000000..3c2ee74be --- /dev/null +++ b/docs/locales/uk/rpc/http/getFeeForMessage.mdx @@ -0,0 +1,80 @@ +--- +sidebarLabel: getFeeForMessage +title: getFeeForMessage RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getFeeForMessage +--- + +Get the fee the network will charge for a particular Message + + + This method is only available in `solana-core` v1.9 or newer. Please use + [getFees](/docs/rpc/deprecated/getFees.mdx) for `solana-core` v1.8 and below. + + + + + + +### Parameters + + + Base-64 encoded Message + + + + +Configuration object containing the following fields: + + + + + The minimum slot that the request can be evaluated at + + + + +### Result + +- `` - Fee corresponding to the message at the specified blockhash + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' +{ + "id":1, + "jsonrpc":"2.0", + "method":"getFeeForMessage", + "params":[ + "AQABAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAA", + { + "commitment":"processed" + } + ] +} +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { "context": { "slot": 5068 }, "value": 5000 }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getFirstAvailableBlock.mdx b/docs/locales/uk/rpc/http/getFirstAvailableBlock.mdx new file mode 100644 index 000000000..c21af52eb --- /dev/null +++ b/docs/locales/uk/rpc/http/getFirstAvailableBlock.mdx @@ -0,0 +1,45 @@ +--- +sidebarLabel: getFirstAvailableBlock +title: getFirstAvailableBlock RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getFirstAvailableBlock +--- + +Returns the slot of the lowest confirmed block that has not been purged from the +ledger + + + + + +### Parameters + +**None** + +### Result + +- `` - Slot + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc":"2.0","id":1, + "method":"getFirstAvailableBlock" + } +' +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": 250000, "id": 1 } +``` + + + diff --git a/docs/locales/uk/rpc/http/getGenesisHash.mdx b/docs/locales/uk/rpc/http/getGenesisHash.mdx new file mode 100644 index 000000000..e7f537644 --- /dev/null +++ b/docs/locales/uk/rpc/http/getGenesisHash.mdx @@ -0,0 +1,45 @@ +--- +sidebarLabel: getGenesisHash +title: getGenesisHash RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getGenesisHash +--- + +Returns the genesis hash + + + + + +### Parameters + +**None** + +### Result + +- `` - a Hash as base-58 encoded string + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getGenesisHash"} +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": "GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC", + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getHealth.mdx b/docs/locales/uk/rpc/http/getHealth.mdx new file mode 100644 index 000000000..48952db2c --- /dev/null +++ b/docs/locales/uk/rpc/http/getHealth.mdx @@ -0,0 +1,78 @@ +--- +sidebarLabel: getHealth +title: getHealth RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getHealth +--- + +Returns the current health of the node. A healthy node is one that is within +`HEALTH_CHECK_SLOT_DISTANCE` slots of the latest cluster confirmed slot. + + + + + +### Parameters + +**None** + +### Result + +If the node is healthy: "ok" + +If the node is unhealthy, a JSON RPC error response is returned. The specifics +of the error response are **UNSTABLE** and may change in the future + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getHealth"} +' +``` + +### Response + +Healthy Result: + +```json +{ "jsonrpc": "2.0", "result": "ok", "id": 1 } +``` + +Unhealthy Result (generic): + +```json +{ + "jsonrpc": "2.0", + "error": { + "code": -32005, + "message": "Node is unhealthy", + "data": {} + }, + "id": 1 +} +``` + +Unhealthy Result (if additional information is available) + +```json +{ + "jsonrpc": "2.0", + "error": { + "code": -32005, + "message": "Node is behind by 42 slots", + "data": { + "numSlotsBehind": 42 + } + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getHighestSnapshotSlot.mdx b/docs/locales/uk/rpc/http/getHighestSnapshotSlot.mdx new file mode 100644 index 000000000..e851c05a0 --- /dev/null +++ b/docs/locales/uk/rpc/http/getHighestSnapshotSlot.mdx @@ -0,0 +1,75 @@ +--- +sidebarLabel: getHighestSnapshotSlot +title: getHighestSnapshotSlot RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getHighestSnapshotSlot +--- + +Returns the highest slot information that the node has snapshots for. + +This will find the highest full snapshot slot, and the highest incremental +snapshot slot _based on_ the full snapshot slot, if there is one. + + + This method is only available in `solana-core` v1.9 or newer. Please use + [getSnapshotSlot](/docs/rpc/http/getSnapshotSlot) for `solana-core` v1.8 and + below. + + + + + + +### Parameters + +**None** + +### Result + +When the node has a snapshot, this returns a JSON object with the following +fields: + +- `full: ` - Highest full snapshot slot +- `incremental: ` - Highest incremental snapshot slot _based on_ + `full` + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1,"method":"getHighestSnapshotSlot"} +' +``` + +### Response + +Result when the node has a snapshot: + +```json +{ + "jsonrpc": "2.0", + "result": { + "full": 100, + "incremental": 110 + }, + "id": 1 +} +``` + +Result when the node has no snapshot: + +```json +{ + "jsonrpc": "2.0", + "error": { "code": -32008, "message": "No snapshot" }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getIdentity.mdx b/docs/locales/uk/rpc/http/getIdentity.mdx new file mode 100644 index 000000000..a027615ad --- /dev/null +++ b/docs/locales/uk/rpc/http/getIdentity.mdx @@ -0,0 +1,50 @@ +--- +sidebarLabel: getIdentity +title: getIdentity RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getIdentity +--- + +Returns the identity pubkey for the current node + + + + + +### Parameters + +**None** + +### Result + +The result field will be a JSON object with the following fields: + +- `identity` - the identity pubkey of the current node \(as a base-58 encoded + string\) + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getIdentity"} +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "identity": "2r1F4iWqVcb8M1DbAjQuFpebkQHY9hcVU4WuW2DJBppN" + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getInflationGovernor.mdx b/docs/locales/uk/rpc/http/getInflationGovernor.mdx new file mode 100644 index 000000000..e93e7bd5e --- /dev/null +++ b/docs/locales/uk/rpc/http/getInflationGovernor.mdx @@ -0,0 +1,71 @@ +--- +sidebarLabel: getInflationGovernor +title: getInflationGovernor RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getInflationGovernor +--- + +Returns the current inflation governor + + + + + +### Parameters + + + +Configuration object containing the following fields: + + + + + +### Result + +The result field will be a JSON object with the following fields: + +- `initial: ` - the initial inflation percentage from time 0 +- `terminal: ` - terminal inflation percentage +- `taper: ` - rate per year at which inflation is lowered. (Rate reduction + is derived using the target slot time in genesis config) +- `foundation: ` - percentage of total inflation allocated to the + foundation +- `foundationTerm: ` - duration of foundation pool inflation in years + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getInflationGovernor"} +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "foundation": 0.05, + "foundationTerm": 7, + "initial": 0.15, + "taper": 0.15, + "terminal": 0.015 + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getInflationRate.mdx b/docs/locales/uk/rpc/http/getInflationRate.mdx new file mode 100644 index 000000000..78120b0c0 --- /dev/null +++ b/docs/locales/uk/rpc/http/getInflationRate.mdx @@ -0,0 +1,56 @@ +--- +sidebarLabel: getInflationRate +title: getInflationRate RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getInflationRate +--- + +Returns the specific inflation values for the current epoch + + + + + +### Parameters + +**None** + +### Result + +The result field will be a JSON object with the following fields: + +- `total: ` - total inflation +- `validator: ` -inflation allocated to validators +- `foundation: ` - inflation allocated to the foundation +- `epoch: ` - epoch for which these values are valid + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getInflationRate"} +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "epoch": 100, + "foundation": 0.001, + "total": 0.149, + "validator": 0.148 + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getInflationReward.mdx b/docs/locales/uk/rpc/http/getInflationReward.mdx new file mode 100644 index 000000000..87d83acf7 --- /dev/null +++ b/docs/locales/uk/rpc/http/getInflationReward.mdx @@ -0,0 +1,96 @@ +--- +sidebarLabel: getInflationReward +title: getInflationReward RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getInflationReward +--- + +Returns the inflation / staking reward for a list of addresses for an epoch + + + + + +### Parameters + + + An array of addresses to query, as base-58 encoded strings + + + + +Configuration object containing the following fields: + + + + + An epoch for which the reward occurs. If omitted, the previous epoch will be + used + + + + The minimum slot that the request can be evaluated at + + + + +### Result + +The result field will be a JSON array with the following fields: + +- `epoch: ` - epoch for which reward occurred +- `effectiveSlot: ` - the slot in which the rewards are effective +- `amount: ` - reward amount in lamports +- `postBalance: ` - post balance of the account in lamports +- `commission: ` - vote account commission when the reward was + credited + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getInflationReward", + "params": [ + [ + "6dmNQ5jwLeLk5REvio1JcMshcbvkYMwy26sJ8pbkvStu", + "BGsqMegLpV6n6Ve146sSX2dTjUMj3M92HnU8BbNRMhF2" + ], + {"epoch": 2} + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": [ + { + "amount": 2500, + "effectiveSlot": 224, + "epoch": 2, + "postBalance": 499999442500 + }, + null + ], + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getLargestAccounts.mdx b/docs/locales/uk/rpc/http/getLargestAccounts.mdx new file mode 100644 index 000000000..6ca86f8a3 --- /dev/null +++ b/docs/locales/uk/rpc/http/getLargestAccounts.mdx @@ -0,0 +1,146 @@ +--- +sidebarLabel: getLargestAccounts +title: getLargestAccounts RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getLargestAccounts +--- + +Returns the 20 largest accounts, by lamport balance (results may be cached up to +two hours) + + + + + +### Parameters + + + +Configuration object containing the following fields: + + + + + filter results by account type + + + + + + +### Result + +The result will be an RpcResponse JSON object with `value` equal to an array of +`` containing: + +- `address: ` - base-58 encoded address of the account +- `lamports: ` - number of lamports in the account, as a u64 + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getLargestAccounts"} +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 54 + }, + "value": [ + { + "lamports": 999974, + "address": "99P8ZgtJYe1buSK8JXkvpLh8xPsCFuLYhz9hQFNw93WJ" + }, + { + "lamports": 42, + "address": "uPwWLo16MVehpyWqsLkK3Ka8nLowWvAHbBChqv2FZeL" + }, + { + "lamports": 42, + "address": "aYJCgU7REfu3XF8b3QhkqgqQvLizx8zxuLBHA25PzDS" + }, + { + "lamports": 42, + "address": "CTvHVtQ4gd4gUcw3bdVgZJJqApXE9nCbbbP4VTS5wE1D" + }, + { + "lamports": 20, + "address": "4fq3xJ6kfrh9RkJQsmVd5gNMvJbuSHfErywvEjNQDPxu" + }, + { + "lamports": 4, + "address": "AXJADheGVp9cruP8WYu46oNkRbeASngN5fPCMVGQqNHa" + }, + { + "lamports": 2, + "address": "8NT8yS6LiwNprgW4yM1jPPow7CwRUotddBVkrkWgYp24" + }, + { + "lamports": 1, + "address": "SysvarEpochSchedu1e111111111111111111111111" + }, + { + "lamports": 1, + "address": "11111111111111111111111111111111" + }, + { + "lamports": 1, + "address": "Stake11111111111111111111111111111111111111" + }, + { + "lamports": 1, + "address": "SysvarC1ock11111111111111111111111111111111" + }, + { + "lamports": 1, + "address": "StakeConfig11111111111111111111111111111111" + }, + { + "lamports": 1, + "address": "SysvarRent111111111111111111111111111111111" + }, + { + "lamports": 1, + "address": "Config1111111111111111111111111111111111111" + }, + { + "lamports": 1, + "address": "SysvarStakeHistory1111111111111111111111111" + }, + { + "lamports": 1, + "address": "SysvarRecentB1ockHashes11111111111111111111" + }, + { + "lamports": 1, + "address": "SysvarFees111111111111111111111111111111111" + }, + { + "lamports": 1, + "address": "Vote111111111111111111111111111111111111111" + } + ] + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getLatestBlockhash.mdx b/docs/locales/uk/rpc/http/getLatestBlockhash.mdx new file mode 100644 index 000000000..b43940402 --- /dev/null +++ b/docs/locales/uk/rpc/http/getLatestBlockhash.mdx @@ -0,0 +1,90 @@ +--- +sidebarLabel: getLatestBlockhash +title: getLatestBlockhash RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getLatestBlockhash +--- + +Returns the latest blockhash + + + This method is only available in `solana-core` v1.9 or newer. Please use + [getRecentBlockhash](/docs/rpc/http/getRecentBlockhash) for `solana-core` v1.8 + and below. + + + + + + +### Parameters + + + +Configuration object containing the following fields: + + + + + The minimum slot that the request can be evaluated at + + + + +### Result + +`RpcResponse` - RpcResponse JSON object with `value` field set to a JSON +object including: + +- `blockhash: ` - a Hash as base-58 encoded string +- `lastValidBlockHeight: ` - last + [block height](/docs/terminology.md#block-height) at which the blockhash will + be valid + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "id":1, + "jsonrpc":"2.0", + "method":"getLatestBlockhash", + "params":[ + { + "commitment":"processed" + } + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 2792 + }, + "value": { + "blockhash": "EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N", + "lastValidBlockHeight": 3090 + } + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getLeaderSchedule.mdx b/docs/locales/uk/rpc/http/getLeaderSchedule.mdx new file mode 100644 index 000000000..4ba0a3bc3 --- /dev/null +++ b/docs/locales/uk/rpc/http/getLeaderSchedule.mdx @@ -0,0 +1,93 @@ +--- +sidebarLabel: getLeaderSchedule +title: getLeaderSchedule RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getLeaderSchedule +--- + +Returns the leader schedule for an epoch + + + + + +### Parameters + + + +Fetch the leader schedule for the epoch that corresponds to the provided slot. + + + If unspecified, the leader schedule for the current epoch is fetched + + + + + + +Configuration object containing the following fields: + + + + + Only return results for this validator identity (base-58 encoded) + + + + +### Result + +Returns a result with one of the two following values: + +- `` - if requested epoch is not found, or +- `` - the result field will be a dictionary of validator identities, as + base-58 encoded strings, and their corresponding leader slot indices as values + (indices are relative to the first slot in the requested epoch) + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getLeaderSchedule", + "params": [ + null, + { + "identity": "4Qkev8aNZcqFNSRhQzwyLMFSsi94jHqE8WNVTJzTP99F" + } + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "4Qkev8aNZcqFNSRhQzwyLMFSsi94jHqE8WNVTJzTP99F": [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63 + ] + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getMaxRetransmitSlot.mdx b/docs/locales/uk/rpc/http/getMaxRetransmitSlot.mdx new file mode 100644 index 000000000..b1f2a1847 --- /dev/null +++ b/docs/locales/uk/rpc/http/getMaxRetransmitSlot.mdx @@ -0,0 +1,42 @@ +--- +sidebarLabel: getMaxRetransmitSlot +title: getMaxRetransmitSlot RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getMaxRetransmitSlot +--- + +Get the max slot seen from retransmit stage. + + + + + +### Parameters + +**None** + +### Result + +`` - Slot number + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getMaxRetransmitSlot"} +' +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": 1234, "id": 1 } +``` + + + diff --git a/docs/locales/uk/rpc/http/getMaxShredInsertSlot.mdx b/docs/locales/uk/rpc/http/getMaxShredInsertSlot.mdx new file mode 100644 index 000000000..059c0fd1d --- /dev/null +++ b/docs/locales/uk/rpc/http/getMaxShredInsertSlot.mdx @@ -0,0 +1,42 @@ +--- +sidebarLabel: getMaxShredInsertSlot +title: getMaxShredInsertSlot RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getMaxShredInsertSlot +--- + +Get the max slot seen from after shred insert. + + + + + +### Parameters + +**None** + +### Result + +`` - Slot number + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getMaxShredInsertSlot"} +' +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": 1234, "id": 1 } +``` + + + diff --git a/docs/locales/uk/rpc/http/getMinimumBalanceForRentExemption.mdx b/docs/locales/uk/rpc/http/getMinimumBalanceForRentExemption.mdx new file mode 100644 index 000000000..11ef41b38 --- /dev/null +++ b/docs/locales/uk/rpc/http/getMinimumBalanceForRentExemption.mdx @@ -0,0 +1,61 @@ +--- +sidebarLabel: getMinimumBalanceForRentExemption +title: getMinimumBalanceForRentExemption RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getMinimumBalanceForRentExemption +--- + +Returns minimum balance required to make account rent exempt. + + + + + +### Parameters + + + the Account's data length + + + + +Configuration object containing the following fields: + + + + + +### Result + +`` - minimum lamports required in the Account to remain rent free + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", "id": 1, + "method": "getMinimumBalanceForRentExemption", + "params": [50] + } +' +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": 500, "id": 1 } +``` + + + diff --git a/docs/locales/uk/rpc/http/getMultipleAccounts.mdx b/docs/locales/uk/rpc/http/getMultipleAccounts.mdx new file mode 100644 index 000000000..ce9312bdc --- /dev/null +++ b/docs/locales/uk/rpc/http/getMultipleAccounts.mdx @@ -0,0 +1,154 @@ +--- +sidebarLabel: getMultipleAccounts +title: getMultipleAccounts RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getMultipleAccounts +--- + +Returns the account information for a list of Pubkeys. + + + + + +### Parameters + + + An array of Pubkeys to query, as base-58 encoded strings (up to a maximum of + 100) + + + + +Configuration object containing the following fields: + + + + + The minimum slot that the request can be evaluated at + + + + Request a slice of the account's data. + +- `length: ` - number of bytes to return +- `offset: ` - byte offset from which to start reading + + + Data slicing is only available for `base58`, `base64`, or `base64+zstd` + encodings. + + + + + + +encoding format for the returned Account data + + + +
+ +- `base58` is slow and limited to less than 129 bytes of Account data. +- `base64` will return base64 encoded data for Account data of any size. +- `base64+zstd` compresses the Account data using + [Zstandard](https://facebook.github.io/zstd/) and base64-encodes the result. +- `jsonParsed` encoding attempts to use program-specific state parsers to return + more human-readable and explicit account state data. +- If `jsonParsed` is requested but a parser cannot be found, the field falls + back to `base64` encoding, detectable when the `data` field is type + ``. + +
+ +
+ +
+ +### Result + +The result will be a JSON object with `value` equal to an array of: + +- `` - if the account at that Pubkey doesn't exist, or +- `` - a JSON object containing: + - `lamports: ` - number of lamports assigned to this account, as a u64 + - `owner: ` - base-58 encoded Pubkey of the program this account has + been assigned to + - `data: <[string, encoding]|object>` - data associated with the account, + either as encoded binary data or JSON format `{: }` - + depending on encoding parameter + - `executable: ` - boolean indicating if the account contains a program + \(and is strictly read-only\) + - `rentEpoch: ` - the epoch at which this account will next owe rent, as + u64 + - `space: ` - the data size of the account + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getMultipleAccounts", + "params": [ + [ + "vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg", + "4fYNw3dojWmQ4dXtSGE9epjRGy9pFSx62YypT7avPYvA" + ], + { + "encoding": "base58" + } + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { "apiVersion": "2.0.15", "slot": 341197247 }, + "value": [ + { + "data": ["", "base58"], + "executable": false, + "lamports": 88849814690250, + "owner": "11111111111111111111111111111111", + "rentEpoch": 18446744073709551615, + "space": 0 + }, + { + "data": ["", "base58"], + "executable": false, + "lamports": 998763433, + "owner": "2WRuhE4GJFoE23DYzp2ij6ZnuQ8p9mJeU6gDgfsjR4or", + "rentEpoch": 18446744073709551615, + "space": 0 + } + ] + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getProgramAccounts.mdx b/docs/locales/uk/rpc/http/getProgramAccounts.mdx new file mode 100644 index 000000000..dd59c122d --- /dev/null +++ b/docs/locales/uk/rpc/http/getProgramAccounts.mdx @@ -0,0 +1,179 @@ +--- +sidebarLabel: getProgramAccounts +title: getProgramAccounts RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getProgramAccounts +--- + +Returns all accounts owned by the provided program Pubkey + + + + + +### Parameters + + + Pubkey of program, as base-58 encoded string + + + + +Configuration object containing the following fields: + + + + + The minimum slot that the request can be evaluated at + + + + wrap the result in an RpcResponse JSON object + + + + +encoding format for the returned Account data + + + +
+ +- `base58` is slow and limited to less than 129 bytes of Account data. +- `base64` will return base64 encoded data for Account data of any size. +- `base64+zstd` compresses the Account data using + [Zstandard](https://facebook.github.io/zstd/) and base64-encodes the result. +- `jsonParsed` encoding attempts to use program-specific state parsers to return + more human-readable and explicit account state data. +- If `jsonParsed` is requested but a parser cannot be found, the field falls + back to `base64` encoding, detectable when the `data` field is type + ``. + +
+ +
+ + + Request a slice of the account's data. + +- `length: ` - number of bytes to return +- `offset: ` - byte offset from which to start reading + + + Data slicing is only available for `base58`, `base64`, or `base64+zstd` + encodings. + + + + + + +filter results using up to 4 filter objects + + + The resultant account(s) must meet **ALL** filter criteria to be included in + the returned results + + + + +
+ +### Result + +By default, the result field will be an array of JSON objects. + + + If the `withContext` flag is set, the array will be wrapped in an + `RpcResponse` JSON object. + + +The resultant response array will contain: + +- `pubkey: ` - the account Pubkey as base-58 encoded string +- `account: ` - a JSON object, with the following sub fields: + - `lamports: ` - number of lamports assigned to this account, as a u64 + - `owner: ` - base-58 encoded Pubkey of the program this account has + been assigned to + - `data: <[string,encoding]|object>` - data associated with the account, + either as encoded binary data or JSON format `{: }` - + depending on encoding parameter + - `executable: ` - boolean indicating if the account contains a program + \(and is strictly read-only\) + - `rentEpoch: ` - the epoch at which this account will next owe rent, as + u64 + - `space: ` - the data size of the account + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getProgramAccounts", + "params": [ + "4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T", + { + "filters": [ + { + "dataSize": 17 + }, + { + "memcmp": { + "offset": 4, + "bytes": "3Mc6vR" + } + } + ] + } + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": [ + { + "account": { + "data": "2R9jLfiAQ9bgdcw6h8s44439", + "executable": false, + "lamports": 15298080, + "owner": "4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T", + "rentEpoch": 28, + "space": 42 + }, + "pubkey": "CxELquR1gPP8wHe33gZ4QxqGB3sZ9RSwsJ2KshVewkFY" + } + ], + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getRecentPerformanceSamples.mdx b/docs/locales/uk/rpc/http/getRecentPerformanceSamples.mdx new file mode 100644 index 000000000..2c431533c --- /dev/null +++ b/docs/locales/uk/rpc/http/getRecentPerformanceSamples.mdx @@ -0,0 +1,100 @@ +--- +sidebarLabel: getRecentPerformanceSamples +title: getRecentPerformanceSamples RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getRecentPerformanceSamples +--- + +Returns a list of recent performance samples, in reverse slot order. Performance +samples are taken every 60 seconds and include the number of transactions and +slots that occur in a given time window. + + + + + +### Parameters + + + +number of samples to return (maximum 720) + + + +### Result + +An array of `RpcPerfSample` with the following fields: + +- `slot: ` - Slot in which sample was taken at +- `numTransactions: ` - Number of transactions processed during the sample + period +- `numSlots: ` - Number of slots completed during the sample period +- `samplePeriodSecs: ` - Number of seconds in a sample window +- `numNonVoteTransactions: ` - Number of non-vote transactions processed + during the sample period. + + + `numNonVoteTransactions` is present starting with v1.15. To get a number of + voting transactions compute: +
+ `numTransactions - numNonVoteTransactions` +
+ + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc":"2.0", "id":1, + "method": "getRecentPerformanceSamples", + "params": [4] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": [ + { + "numSlots": 126, + "numTransactions": 126, + "numNonVoteTransactions": 1, + "samplePeriodSecs": 60, + "slot": 348125 + }, + { + "numSlots": 126, + "numTransactions": 126, + "numNonVoteTransactions": 1, + "samplePeriodSecs": 60, + "slot": 347999 + }, + { + "numSlots": 125, + "numTransactions": 125, + "numNonVoteTransactions": 0, + "samplePeriodSecs": 60, + "slot": 347873 + }, + { + "numSlots": 125, + "numTransactions": 125, + "numNonVoteTransactions": 0, + "samplePeriodSecs": 60, + "slot": 347748 + } + ], + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getRecentPrioritizationFees.mdx b/docs/locales/uk/rpc/http/getRecentPrioritizationFees.mdx new file mode 100644 index 000000000..25359e528 --- /dev/null +++ b/docs/locales/uk/rpc/http/getRecentPrioritizationFees.mdx @@ -0,0 +1,93 @@ +--- +sidebarLabel: getRecentPrioritizationFees +title: getRecentPrioritizationFees RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getRecentPrioritizationFees +--- + +Returns a list of prioritization fees from recent blocks. + + + Currently, a node's prioritization-fee cache stores data from up to 150 + blocks. + + + + + + +### Parameters + + + +An array of Account addresses (up to a maximum of 128 addresses), as base-58 +encoded strings + + + If this parameter is provided, the response will reflect a fee to land a + transaction locking all of the provided accounts as writable. + + + + +### Result + +An array of `RpcPrioritizationFee` with the following fields: + +- `slot: ` - slot in which the fee was observed +- `prioritizationFee: ` - the per-compute-unit fee paid by at least one + successfully landed transaction, specified in increments of micro-lamports + (0.000001 lamports) + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc":"2.0", "id":1, + "method": "getRecentPrioritizationFees", + "params": [ + ["CxELquR1gPP8wHe33gZ4QxqGB3sZ9RSwsJ2KshVewkFY"] + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": [ + { + "slot": 348125, + "prioritizationFee": 0 + }, + { + "slot": 348126, + "prioritizationFee": 1000 + }, + { + "slot": 348127, + "prioritizationFee": 500 + }, + { + "slot": 348128, + "prioritizationFee": 0 + }, + { + "slot": 348129, + "prioritizationFee": 1234 + } + ], + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getSignatureStatuses.mdx b/docs/locales/uk/rpc/http/getSignatureStatuses.mdx new file mode 100644 index 000000000..bf101e360 --- /dev/null +++ b/docs/locales/uk/rpc/http/getSignatureStatuses.mdx @@ -0,0 +1,115 @@ +--- +sidebarLabel: getSignatureStatuses +title: getSignatureStatuses RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getSignatureStatuses +--- + +Returns the statuses of a list of signatures. Each signature must be a +[txid](/docs/terminology.md#transaction-id), the first signature of a +transaction. + + + Unless the `searchTransactionHistory` configuration parameter is included, + this method only searches the recent status cache of signatures, which retains + statuses for all active slots plus `MAX_RECENT_BLOCKHASHES` rooted slots. + + + + + + +### Parameters + + + An array of transaction signatures to confirm, as base-58 encoded strings (up + to a maximum of 256) + + + + +Configuration object containing the following fields: + + + +if `true` - a Solana node will search its ledger cache for any signatures not +found in the recent status cache + + + + + +### Result + +An array of `RpcResponse` consisting of either: + +- `` - Unknown transaction, or +- `` + - `slot: ` - The slot the transaction was processed + - `confirmations: ` - Number of blocks since signature + confirmation, null if rooted, as well as finalized by a supermajority of the + cluster + - `err: ` - Error if transaction failed, null if transaction + succeeded. See + [TransactionError definitions](https://github.com/solana-labs/solana/blob/c0c60386544ec9a9ec7119229f37386d9f070523/sdk/src/transaction/error.rs#L13) + - `confirmationStatus: ` - The transaction's cluster confirmation + status; Either `processed`, `confirmed`, or `finalized`. See + [Commitment](/docs/rpc/index.mdx#configuring-state-commitment) for more on + optimistic confirmation. + - DEPRECATED: `status: ` - Transaction status + - `"Ok": ` - Transaction was successful + - `"Err": ` - Transaction failed with TransactionError + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getSignatureStatuses", + "params": [ + [ + "5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW" + ], + { + "searchTransactionHistory": true + } + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 82 + }, + "value": [ + { + "slot": 48, + "confirmations": null, + "err": null, + "status": { + "Ok": null + }, + "confirmationStatus": "finalized" + }, + null + ] + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getSignaturesForAddress.mdx b/docs/locales/uk/rpc/http/getSignaturesForAddress.mdx new file mode 100644 index 000000000..2587fa931 --- /dev/null +++ b/docs/locales/uk/rpc/http/getSignaturesForAddress.mdx @@ -0,0 +1,115 @@ +--- +sidebarLabel: getSignaturesForAddress +title: getSignaturesForAddress RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getSignaturesForAddress +--- + +Returns signatures for confirmed transactions that include the given address in +their `accountKeys` list. Returns signatures backwards in time from the provided +signature or most recent confirmed block + + + + + +### Parameters + + + Account address as base-58 encoded string + + + + +Configuration object containing the following fields: + + + + + The minimum slot that the request can be evaluated at + + + + maximum transaction signatures to return (between 1 and 1,000). + + + + start searching backwards from this transaction signature. If not provided the + search starts from the top of the highest max confirmed block. + + + + search until this transaction signature, if found before limit reached + + + + +### Result + +An array of ``, ordered from **newest** to **oldest** transaction, +containing transaction signature information with the following fields: + +- `signature: ` - transaction signature as base-58 encoded string +- `slot: ` - The slot that contains the block with the transaction +- `err: ` - Error if transaction failed, null if transaction + succeeded. See + [TransactionError definitions](https://github.com/solana-labs/solana/blob/c0c60386544ec9a9ec7119229f37386d9f070523/sdk/src/transaction/error.rs#L13) + for more info. +- `memo: ` - Memo associated with the transaction, null if no memo + is present +- `blockTime: ` - estimated production time, as Unix timestamp + (seconds since the Unix epoch) of when transaction was processed. null if not + available. +- `confirmationStatus: ` - The transaction's cluster confirmation + status; Either `processed`, `confirmed`, or `finalized`. See + [Commitment](/docs/rpc/index.mdx#configuring-state-commitment) for more on + optimistic confirmation. + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getSignaturesForAddress", + "params": [ + "Vote111111111111111111111111111111111111111", + { + "limit": 1 + } + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": [ + { + "err": null, + "memo": null, + "signature": "5h6xBEauJ3PK6SWCZ1PGjBvj8vDdWG3KpwATGy1ARAXFSDwt8GFXM7W5Ncn16wmqokgpiKRLuS83KUxyZyv2sUYv", + "slot": 114, + "blockTime": null + } + ], + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getSlot.mdx b/docs/locales/uk/rpc/http/getSlot.mdx new file mode 100644 index 000000000..504c6c323 --- /dev/null +++ b/docs/locales/uk/rpc/http/getSlot.mdx @@ -0,0 +1,58 @@ +--- +sidebarLabel: getSlot +title: getSlot RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getSlot +--- + +Returns the slot that has reached the +[given or default commitment level](/docs/rpc/index.mdx#configuring-state-commitment) + + + + + +### Parameters + + + +Configuration object containing the following fields: + + + + + The minimum slot that the request can be evaluated at + + + + +### Result + +`` - Current slot + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getSlot"} +' +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": 1234, "id": 1 } +``` + + + diff --git a/docs/locales/uk/rpc/http/getSlotLeader.mdx b/docs/locales/uk/rpc/http/getSlotLeader.mdx new file mode 100644 index 000000000..355c9c024 --- /dev/null +++ b/docs/locales/uk/rpc/http/getSlotLeader.mdx @@ -0,0 +1,61 @@ +--- +sidebarLabel: getSlotLeader +title: getSlotLeader RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getSlotLeader +--- + +Returns the current slot leader + + + + + +### Parameters + + + +Configuration object containing the following fields: + + + + + The minimum slot that the request can be evaluated at + + + + +### Result + +`` - Node identity Pubkey as base-58 encoded string + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getSlotLeader"} +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": "ENvAW7JScgYq6o4zKZwewtkzzJgDzuJAFxYasvmEQdpS", + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getSlotLeaders.mdx b/docs/locales/uk/rpc/http/getSlotLeaders.mdx new file mode 100644 index 000000000..2b095babd --- /dev/null +++ b/docs/locales/uk/rpc/http/getSlotLeaders.mdx @@ -0,0 +1,73 @@ +--- +sidebarLabel: getSlotLeaders +title: getSlotLeaders RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getSlotLeaders +--- + +Returns the slot leaders for a given slot range + + + + + +### Parameters + + + Start slot, as u64 integer + + + + Limit, as u64 integer (between 1 and 5,000) + + +### Result + +`` - array of Node identity public keys as base-58 encoded +strings + + + + + +### Code sample + +If the current slot is `#99` - query the next `10` leaders with the following +request: + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc":"2.0", "id": 1, + "method": "getSlotLeaders", + "params": [100, 10] + } +' +``` + +### Response + +The first leader returned is the leader for slot `#100`: + +```json +{ + "jsonrpc": "2.0", + "result": [ + "ChorusmmK7i1AxXeiTtQgQZhQNiXYU84ULeaYF1EH15n", + "ChorusmmK7i1AxXeiTtQgQZhQNiXYU84ULeaYF1EH15n", + "ChorusmmK7i1AxXeiTtQgQZhQNiXYU84ULeaYF1EH15n", + "ChorusmmK7i1AxXeiTtQgQZhQNiXYU84ULeaYF1EH15n", + "Awes4Tr6TX8JDzEhCZY2QVNimT6iD1zWHzf1vNyGvpLM", + "Awes4Tr6TX8JDzEhCZY2QVNimT6iD1zWHzf1vNyGvpLM", + "Awes4Tr6TX8JDzEhCZY2QVNimT6iD1zWHzf1vNyGvpLM", + "Awes4Tr6TX8JDzEhCZY2QVNimT6iD1zWHzf1vNyGvpLM", + "DWvDTSh3qfn88UoQTEKRV2JnLt5jtJAVoiCo3ivtMwXP", + "DWvDTSh3qfn88UoQTEKRV2JnLt5jtJAVoiCo3ivtMwXP" + ], + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getStakeMinimumDelegation.mdx b/docs/locales/uk/rpc/http/getStakeMinimumDelegation.mdx new file mode 100644 index 000000000..b98f1a359 --- /dev/null +++ b/docs/locales/uk/rpc/http/getStakeMinimumDelegation.mdx @@ -0,0 +1,67 @@ +--- +sidebarLabel: getStakeMinimumDelegation +title: getStakeMinimumDelegation RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getStakeMinimumDelegation +--- + +Returns the stake minimum delegation, in lamports. + + + + + +### Parameters + + + +Configuration object containing the following fields: + + + + + +### Result + +The result will be an RpcResponse JSON object with `value` equal to: + +- `` - The stake minimum delegation, in lamports + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc":"2.0", "id":1, + "method": "getStakeMinimumDelegation" + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 501 + }, + "value": 1000000000 + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getSupply.mdx b/docs/locales/uk/rpc/http/getSupply.mdx new file mode 100644 index 000000000..ebd60fa00 --- /dev/null +++ b/docs/locales/uk/rpc/http/getSupply.mdx @@ -0,0 +1,84 @@ +--- +sidebarLabel: getSupply +title: getSupply RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getSupply +--- + +Returns information about the current supply. + + + + + +### Parameters + + + +Configuration object containing the following fields: + + + + + exclude non circulating accounts list from response + + + + +### Result + +The result will be an RpcResponse JSON object with `value` equal to a JSON +object containing: + +- `total: ` - Total supply in lamports +- `circulating: ` - Circulating supply in lamports +- `nonCirculating: ` - Non-circulating supply in lamports +- `nonCirculatingAccounts: ` - an array of account addresses of + non-circulating accounts, as strings. If `excludeNonCirculatingAccountsList` + is enabled, the returned array will be empty. + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0", "id":1, "method":"getSupply"} +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 1114 + }, + "value": { + "circulating": 16000, + "nonCirculating": 1000000, + "nonCirculatingAccounts": [ + "FEy8pTbP5fEoqMV1GdTz83byuA8EKByqYat1PKDgVAq5", + "9huDUZfxoJ7wGMTffUE7vh1xePqef7gyrLJu9NApncqA", + "3mi1GmwEE3zo2jmfDuzvjSX9ovRXsDUKHvsntpkhuLJ9", + "BYxEJTDerkaRWBem3XgnVcdhppktBXa2HbkHPKj2Ui4Z" + ], + "total": 1016000 + } + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getTokenAccountBalance.mdx b/docs/locales/uk/rpc/http/getTokenAccountBalance.mdx new file mode 100644 index 000000000..dfef4c521 --- /dev/null +++ b/docs/locales/uk/rpc/http/getTokenAccountBalance.mdx @@ -0,0 +1,90 @@ +--- +sidebarLabel: getTokenAccountBalance +title: getTokenAccountBalance RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getTokenAccountBalance +--- + +Returns the token balance of an SPL Token account. + + + + + +### Parameters + + + Pubkey of Token account to query, as base-58 encoded string + + + + +Configuration object containing the following fields: + + + + + +### Result + +The result will be an RpcResponse JSON object with `value` equal to a JSON +object containing: + +- `amount: ` - the raw balance without decimals, a string representation + of u64 +- `decimals: ` - number of base 10 digits to the right of the decimal place +- `uiAmount: ` - the balance, using mint-prescribed decimals + **DEPRECATED** +- `uiAmountString: ` - the balance as a string, using mint-prescribed + decimals + +For more details on returned data, the +[Token Balances Structure](/docs/rpc/json-structures#token-balances) response +from [getBlock](/docs/rpc/http/getblock) follows a similar structure. + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", "id": 1, + "method": "getTokenAccountBalance", + "params": [ + "7fUAJdStEuGbc3sM84cKRL6yYaaSstyLSU4ve5oovLS7" + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 1114 + }, + "value": { + "amount": "9864", + "decimals": 2, + "uiAmount": 98.64, + "uiAmountString": "98.64" + } + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getTokenAccountsByDelegate.mdx b/docs/locales/uk/rpc/http/getTokenAccountsByDelegate.mdx new file mode 100644 index 000000000..619f743ac --- /dev/null +++ b/docs/locales/uk/rpc/http/getTokenAccountsByDelegate.mdx @@ -0,0 +1,189 @@ +--- +sidebarLabel: getTokenAccountsByDelegate +title: getTokenAccountsByDelegate RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getTokenAccountsByDelegate +--- + +Returns all SPL Token accounts by approved Delegate. + + + + + +### Parameters + + + Pubkey of account delegate to query, as base-58 encoded string + + + + +A JSON object with one of the following fields: + +- `mint: ` - Pubkey of the specific token Mint to limit accounts to, as + base-58 encoded string; or +- `programId: ` - Pubkey of the Token program that owns the accounts, as + base-58 encoded string + + + + + +Configuration object containing the following fields: + + + + + The minimum slot that the request can be evaluated at + + + + Request a slice of the account's data. + +- `length: ` - number of bytes to return +- `offset: ` - byte offset from which to start reading + + + Data slicing is only available for `base58`, `base64`, or `base64+zstd` + encodings. + + + + + + +Encoding format for Account data + + + +
+ +- `base58` is slow and limited to less than 129 bytes of Account data. +- `base64` will return base64 encoded data for Account data of any size. +- `base64+zstd` compresses the Account data using + [Zstandard](https://facebook.github.io/zstd/) and base64-encodes the result. +- `jsonParsed` encoding attempts to use program-specific state parsers to return + more human-readable and explicit account state data. +- If `jsonParsed` is requested but a parser cannot be found, the field falls + back to `base64` encoding, detectable when the `data` field is type `string`. + +
+ +
+ +
+ +### Result + +The result will be an RpcResponse JSON object with `value` equal to an array of +JSON objects, which will contain: + +- `pubkey: ` - the account Pubkey as base-58 encoded string +- `account: ` - a JSON object, with the following sub fields: + - `lamports: ` - number of lamports assigned to this account, as a u64 + - `owner: ` - base-58 encoded Pubkey of the program this account has + been assigned to + - `data: ` - Token state data associated with the account, either as + encoded binary data or in JSON format `{: }` + - `executable: ` - boolean indicating if the account contains a program + (and is strictly read-only\) + - `rentEpoch: ` - the epoch at which this account will next owe rent, as + u64 + - `space: ` - the data size of the account + +When the data is requested with the `jsonParsed` encoding a format similar to +that of the [Token Balances Structure](/docs/rpc/json-structures#token-balances) +can be expected inside the structure, both for the `tokenAmount` and the +`delegatedAmount` - with the latter being an optional object. + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getTokenAccountsByDelegate", + "params": [ + "4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T", + { + "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "encoding": "jsonParsed" + } + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 1114 + }, + "value": [ + { + "account": { + "data": { + "program": "spl-token", + "parsed": { + "info": { + "tokenAmount": { + "amount": "1", + "decimals": 1, + "uiAmount": 0.1, + "uiAmountString": "0.1" + }, + "delegate": "4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T", + "delegatedAmount": { + "amount": "1", + "decimals": 1, + "uiAmount": 0.1, + "uiAmountString": "0.1" + }, + "state": "initialized", + "isNative": false, + "mint": "3wyAj7Rt1TWVPZVteFJPLa26JmLvdb1CAKEFZm3NY75E", + "owner": "CnPoSPKXu7wJqxe59Fs72tkBeALovhsCxYeFwPCQH9TD" + }, + "type": "account" + }, + "space": 165 + }, + "executable": false, + "lamports": 1726080, + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "rentEpoch": 4, + "space": 165 + }, + "pubkey": "28YTZEwqtMHWrhWcvv34se7pjS7wctgqzCPB3gReCFKp" + } + ] + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getTokenAccountsByOwner.mdx b/docs/locales/uk/rpc/http/getTokenAccountsByOwner.mdx new file mode 100644 index 000000000..a6d1677b2 --- /dev/null +++ b/docs/locales/uk/rpc/http/getTokenAccountsByOwner.mdx @@ -0,0 +1,209 @@ +--- +sidebarLabel: getTokenAccountsByOwner +title: getTokenAccountsByOwner RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getTokenAccountsByOwner +--- + +Returns all SPL Token accounts by token owner. + + + + + +### Parameters + + + Pubkey of account delegate to query, as base-58 encoded string + + + + +A JSON object with either one of the following fields: + +- `mint: ` - Pubkey of the specific token Mint to limit accounts to, as + base-58 encoded string; or +- `programId: ` - Pubkey of the Token program that owns the accounts, as + base-58 encoded string + + + + + +Configuration object containing the following fields: + + + + + The minimum slot that the request can be evaluated at + + + + Request a slice of the account's data. + +- `length: ` - number of bytes to return +- `offset: ` - byte offset from which to start reading + + + Data slicing is only available for `base58`, `base64`, or `base64+zstd` + encodings. + + + + + + +Encoding format for Account data + + + +
+ +- `base58` is slow and limited to less than 129 bytes of Account data. +- `base64` will return base64 encoded data for Account data of any size. +- `base64+zstd` compresses the Account data using + [Zstandard](https://facebook.github.io/zstd/) and base64-encodes the result. +- `jsonParsed` encoding attempts to use program-specific state parsers to return + more human-readable and explicit account state data. +- If `jsonParsed` is requested but a parser cannot be found, the field falls + back to `base64` encoding, detectable when the `data` field is type `string`. + +
+ +
+ +
+ +### Result + +The result will be an RpcResponse JSON object with `value` equal to an array of +JSON objects, which will contain: + +- `pubkey: ` - the account Pubkey as base-58 encoded string +- `account: ` - a JSON object, with the following sub fields: + - `lamports: ` - number of lamports assigned to this account, as a u64 + - `owner: ` - base-58 encoded Pubkey of the program this account has + been assigned to + - `data: ` - Token state data associated with the account, either as + encoded binary data or in JSON format `{: }` + - `executable: ` - boolean indicating if the account contains a program + \(and is strictly read-only\) + - `rentEpoch: ` - the epoch at which this account will next owe rent, as + u64 + - `space: ` - the data size of the account + +When the data is requested with the `jsonParsed` encoding a format similar to +that of the [Token Balances Structure](/docs/rpc/json-structures#token-balances) +can be expected inside the structure, both for the `tokenAmount` and the +`delegatedAmount` - with the latter being an optional object. + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getTokenAccountsByOwner", + "params": [ + "A1TMhSGzQxMr1TboBKtgixKz1sS6REASMxPo1qsyTSJd", + { + "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "encoding": "jsonParsed" + } + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { "apiVersion": "2.0.15", "slot": 341197933 }, + "value": [ + { + "account": { + "data": { + "parsed": { + "info": { + "isNative": false, + "mint": "2cHr7QS3xfuSV8wdxo3ztuF4xbiarF6Nrgx3qpx3HzXR", + "owner": "A1TMhSGzQxMr1TboBKtgixKz1sS6REASMxPo1qsyTSJd", + "state": "initialized", + "tokenAmount": { + "amount": "420000000000000", + "decimals": 6, + "uiAmount": 420000000.0, + "uiAmountString": "420000000" + } + }, + "type": "account" + }, + "program": "spl-token", + "space": 165 + }, + "executable": false, + "lamports": 2039280, + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "rentEpoch": 18446744073709551615, + "space": 165 + }, + "pubkey": "BGocb4GEpbTFm8UFV2VsDSaBXHELPfAXrvd4vtt8QWrA" + }, + { + "account": { + "data": { + "parsed": { + "info": { + "isNative": false, + "mint": "4KVSsAtsG8JByKfB2jYWgGwvVR9WcBSUfsqpTSL9c3Jr", + "owner": "A1TMhSGzQxMr1TboBKtgixKz1sS6REASMxPo1qsyTSJd", + "state": "initialized", + "tokenAmount": { + "amount": "10000000000000", + "decimals": 9, + "uiAmount": 10000.0, + "uiAmountString": "10000" + } + }, + "type": "account" + }, + "program": "spl-token", + "space": 165 + }, + "executable": false, + "lamports": 2039280, + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "rentEpoch": 18446744073709551615, + "space": 165 + }, + "pubkey": "9PwCPoWJ75LSgZeGMubXBdufYMVd66HrcF78QzW6ZHkV" + } + ] + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getTokenLargestAccounts.mdx b/docs/locales/uk/rpc/http/getTokenLargestAccounts.mdx new file mode 100644 index 000000000..3702a0ad7 --- /dev/null +++ b/docs/locales/uk/rpc/http/getTokenLargestAccounts.mdx @@ -0,0 +1,97 @@ +--- +sidebarLabel: getTokenLargestAccounts +title: getTokenLargestAccounts RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getTokenLargestAccounts +--- + +Returns the 20 largest accounts of a particular SPL Token type. + + + + + +### Parameters + + + Pubkey of the token Mint to query, as base-58 encoded string + + + + +Configuration object containing the following fields: + + + + + +### Result + +The result will be an RpcResponse JSON object with `value` equal to an array of +JSON objects containing: + +- `address: ` - the address of the token account +- `amount: ` - the raw token account balance without decimals, a string + representation of u64 +- `decimals: ` - number of base 10 digits to the right of the decimal place +- `uiAmount: ` - the token account balance, using mint-prescribed + decimals **DEPRECATED** +- `uiAmountString: ` - the token account balance as a string, using + mint-prescribed decimals + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", "id": 1, + "method": "getTokenLargestAccounts", + "params": [ + "3wyAj7Rt1TWVPZVteFJPLa26JmLvdb1CAKEFZm3NY75E" + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 1114 + }, + "value": [ + { + "address": "FYjHNoFtSQ5uijKrZFyYAxvEr87hsKXkXcxkcmkBAf4r", + "amount": "771", + "decimals": 2, + "uiAmount": 7.71, + "uiAmountString": "7.71" + }, + { + "address": "BnsywxTcaYeNUtzrPxQUvzAWxfzZe3ZLUJ4wMMuLESnu", + "amount": "229", + "decimals": 2, + "uiAmount": 2.29, + "uiAmountString": "2.29" + } + ] + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getTokenSupply.mdx b/docs/locales/uk/rpc/http/getTokenSupply.mdx new file mode 100644 index 000000000..193f79d48 --- /dev/null +++ b/docs/locales/uk/rpc/http/getTokenSupply.mdx @@ -0,0 +1,86 @@ +--- +sidebarLabel: getTokenSupply +title: getTokenSupply RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getTokenSupply +--- + +Returns the total supply of an SPL Token type. + + + + + +### Parameters + + + Pubkey of the token Mint to query, as base-58 encoded string + + + + +Configuration object containing the following fields: + + + + + +### Result + +The result will be an RpcResponse JSON object with `value` equal to a JSON +object containing: + +- `amount: ` - the raw total token supply without decimals, a string + representation of u64 +- `decimals: ` - number of base 10 digits to the right of the decimal place +- `uiAmount: ` - the total token supply, using mint-prescribed + decimals **DEPRECATED** +- `uiAmountString: ` - the total token supply as a string, using + mint-prescribed decimals + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", "id": 1, + "method": "getTokenSupply", + "params": [ + "3wyAj7Rt1TWVPZVteFJPLa26JmLvdb1CAKEFZm3NY75E" + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 1114 + }, + "value": { + "amount": "100000", + "decimals": 2, + "uiAmount": 1000, + "uiAmountString": "1000" + } + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getTransaction.mdx b/docs/locales/uk/rpc/http/getTransaction.mdx new file mode 100644 index 000000000..1fa973600 --- /dev/null +++ b/docs/locales/uk/rpc/http/getTransaction.mdx @@ -0,0 +1,213 @@ +--- +sidebarLabel: getTransaction +title: getTransaction RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getTransaction +--- + +Returns transaction details for a confirmed transaction + + + + + +### Parameters + + + Transaction signature, as base-58 encoded string + + + + +Configuration object containing the following fields: + + + +- `processed` is not supported. + + + + + Set the max transaction version to return in responses. If the requested + transaction is a higher version, an error will be returned. If this parameter + is omitted, only legacy transactions will be returned, and any versioned + transaction will prompt the error. + + + + +Encoding for the returned Transaction + + + +
+ +- `jsonParsed` encoding attempts to use program-specific state parsers to return + more human-readable and explicit data in the + `transaction.message.instructions` list. +- If `jsonParsed` is requested but a parser cannot be found, the instruction + falls back to regular JSON encoding (`accounts`, `data`, and `programIdIndex` + fields). + +
+ +
+ +
+ +### Result + +- `` - if transaction is not found or not confirmed +- `` - if transaction is confirmed, an object with the following fields: + - `slot: ` - the slot this transaction was processed in + - `transaction: ` - + [Transaction](/docs/rpc/json-structures#transactions) object, either in JSON + format or encoded binary data, depending on encoding parameter + - `blockTime: ` - estimated production time, as Unix timestamp + (seconds since the Unix epoch) of when the transaction was processed. null + if not available + - `meta: ` - transaction status metadata object: + - `err: ` - Error if transaction failed, null if transaction + succeeded. + [TransactionError definitions](https://docs.rs/solana-sdk/latest/solana_sdk/transaction/enum.TransactionError.html) + - `fee: ` - fee this transaction was charged, as u64 integer + - `preBalances: ` - array of u64 account balances from before the + transaction was processed + - `postBalances: ` - array of u64 account balances after the + transaction was processed + - `innerInstructions: ` - List of + [inner instructions](/docs/rpc/json-structures#inner-instructions) or + `null` if inner instruction recording was not enabled during this + transaction + - `preTokenBalances: ` - List of + [token balances](/docs/rpc/json-structures#token-balances) from before the + transaction was processed or omitted if token balance recording was not + yet enabled during this transaction + - `postTokenBalances: ` - List of + [token balances](/docs/rpc/json-structures#token-balances) from after the + transaction was processed or omitted if token balance recording was not + yet enabled during this transaction + - `logMessages: ` - array of string log messages or `null` if + log message recording was not enabled during this transaction + - DEPRECATED: `status: ` - Transaction status + - `"Ok": ` - Transaction was successful + - `"Err": ` - Transaction failed with TransactionError + - `rewards: ` - transaction-level rewards, populated if rewards + are requested; an array of JSON objects containing: + - `pubkey: ` - The public key, as base-58 encoded string, of the + account that received the reward + - `lamports: `- number of reward lamports credited or debited by the + account, as a i64 + - `postBalance: ` - account balance in lamports after the reward was + applied + - `rewardType: ` - type of reward: currently only "rent", other + types may be added in the future + - `commission: ` - vote account commission when the reward + was credited, only present for voting and staking rewards + - `loadedAddresses: ` - Transaction addresses loaded from + address lookup tables. Undefined if `maxSupportedTransactionVersion` is + not set in request params, or if `jsonParsed` encoding is set in request + params. + - `writable: ` - Ordered list of base-58 encoded addresses + for writable loaded accounts + - `readonly: ` - Ordered list of base-58 encoded addresses + for readonly loaded accounts + - `returnData: ` - the most-recent return data generated + by an instruction in the transaction, with the following fields: + - `programId: ` - the program that generated the return data, as + base-58 encoded Pubkey + - `data: <[string, encoding]>` - the return data itself, as base-64 + encoded binary data + - `computeUnitsConsumed: ` - number of + [compute units](/docs/core/fees.md#compute-budget) consumed by the + transaction + - `version: <"legacy"|number|undefined>` - Transaction version. Undefined if + `maxSupportedTransactionVersion` is not set in request params. + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getTransaction", + "params": [ + "2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv", + "json" + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "meta": { + "err": null, + "fee": 5000, + "innerInstructions": [], + "postBalances": [499998932500, 26858640, 1, 1, 1], + "postTokenBalances": [], + "preBalances": [499998937500, 26858640, 1, 1, 1], + "preTokenBalances": [], + "rewards": [], + "status": { + "Ok": null + } + }, + "slot": 430, + "transaction": { + "message": { + "accountKeys": [ + "3UVYmECPPMZSCqWKfENfuoTv51fTDTWicX9xmBD2euKe", + "AjozzgE83A3x1sHNUR64hfH7zaEBWeMaFuAN9kQgujrc", + "SysvarS1otHashes111111111111111111111111111", + "SysvarC1ock11111111111111111111111111111111", + "Vote111111111111111111111111111111111111111" + ], + "header": { + "numReadonlySignedAccounts": 0, + "numReadonlyUnsignedAccounts": 3, + "numRequiredSignatures": 1 + }, + "instructions": [ + { + "accounts": [1, 2, 3, 0], + "data": "37u9WtQpcm6ULa3WRQHmj49EPs4if7o9f1jSRVZpm2dvihR9C8jY4NqEwXUbLwx15HBSNcP1", + "programIdIndex": 4 + } + ], + "recentBlockhash": "mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B" + }, + "signatures": [ + "2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv" + ] + } + }, + "blockTime": null, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getTransactionCount.mdx b/docs/locales/uk/rpc/http/getTransactionCount.mdx new file mode 100644 index 000000000..d3b07b6c7 --- /dev/null +++ b/docs/locales/uk/rpc/http/getTransactionCount.mdx @@ -0,0 +1,57 @@ +--- +sidebarLabel: getTransactionCount +title: getTransactionCount RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getTransactionCount +--- + +Returns the current Transaction count from the ledger + + + + + +### Parameters + + + +Configuration object containing the following fields: + + + + + The minimum slot that the request can be evaluated at + + + + +### Result + +`` - the current Transaction count from the ledger + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getTransactionCount"} +' +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": 268, "id": 1 } +``` + + + diff --git a/docs/locales/uk/rpc/http/getVersion.mdx b/docs/locales/uk/rpc/http/getVersion.mdx new file mode 100644 index 000000000..5aeb25ea1 --- /dev/null +++ b/docs/locales/uk/rpc/http/getVersion.mdx @@ -0,0 +1,50 @@ +--- +sidebarLabel: getVersion +title: getVersion RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getVersion +--- + +Returns the current Solana version running on the node + + + + + +### Parameters + +**None** + +### Result + +The result field will be a JSON object with the following fields: + +- `solana-core` - software version of solana-core as a `string` +- `feature-set` - unique identifier of the current software's feature set as a + `u32` + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"getVersion"} +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { "feature-set": 2891131721, "solana-core": "1.16.7" }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/getVoteAccounts.mdx b/docs/locales/uk/rpc/http/getVoteAccounts.mdx new file mode 100644 index 000000000..2ba1257d8 --- /dev/null +++ b/docs/locales/uk/rpc/http/getVoteAccounts.mdx @@ -0,0 +1,113 @@ +--- +sidebarLabel: getVoteAccounts +title: getVoteAccounts RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/getVoteAccounts +--- + +Returns the account info and associated stake for all the voting accounts in the +current bank. + + + + + +### Parameters + + + +Configuration object containing the following fields: + + + + + Only return results for this validator vote address (base-58 encoded) + + + + Do not filter out delinquent validators with no stake + + + + Specify the number of slots behind the tip that a validator must fall to be + considered delinquent. **NOTE:** For the sake of consistency between ecosystem + products, _it is **not** recommended that this argument be specified._ + + + + +### Result + +The result field will be a JSON object of `current` and `delinquent` accounts, +each containing an array of JSON objects with the following sub fields: + +- `votePubkey: ` - Vote account address, as base-58 encoded string +- `nodePubkey: ` - Validator identity, as base-58 encoded string +- `activatedStake: ` - the stake, in lamports, delegated to this vote + account and active in this epoch +- `epochVoteAccount: ` - bool, whether the vote account is staked for this + epoch +- `commission: ` - percentage (0-100) of rewards payout owed to the vote + account +- `lastVote: ` - Most recent slot voted on by this vote account +- `epochCredits: ` - Latest history of earned credits for up to five + epochs, as an array of arrays containing: `[epoch, credits, previousCredits]`. +- `rootSlot: ` - Current root slot for this vote account + + + + + +### Code sample + +Restrict results to a single validator vote account: + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getVoteAccounts", + "params": [ + { + "votePubkey": "3ZT31jkAGhUaw8jsy4bTknwBMP8i4Eueh52By4zXcsVw" + } + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "current": [ + { + "commission": 0, + "epochVoteAccount": true, + "epochCredits": [ + [1, 64, 0], + [2, 192, 64] + ], + "nodePubkey": "B97CCUW3AEZFGy6uUg6zUdnNYvnVq5VG8PUtb2HayTDD", + "lastVote": 147, + "activatedStake": 42, + "votePubkey": "3ZT31jkAGhUaw8jsy4bTknwBMP8i4Eueh52By4zXcsVw" + } + ], + "delinquent": [] + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/index.mdx b/docs/locales/uk/rpc/http/index.mdx new file mode 100644 index 000000000..0392e5605 --- /dev/null +++ b/docs/locales/uk/rpc/http/index.mdx @@ -0,0 +1,105 @@ +--- +title: Solana RPC HTTP Methods +seoTitle: Solana RPC HTTP Methods +sidebarLabel: HTTP Methods +sidebarSortOrder: 1 +hideTableOfContents: false +--- + +Solana nodes accept HTTP requests using the +[JSON-RPC 2.0](https://www.jsonrpc.org/specification) specification. + +> For JavaScript applications, use the +> [@solana/web3.js](https://github.com/solana-labs/solana-web3.js) library as a +> convenient interface for the RPC methods to interact with a Solana node. For +> an PubSub connection to a Solana node, use the +> [Websocket API](/docs/rpc/websocket/index.mdx). + +## RPC HTTP Endpoint + +Default port: `8899` + +- http://localhost:8899 +- http://192.168.1.88:8899 + +## Request Formatting + +To make a JSON-RPC request, send an HTTP POST request with a +`Content-Type: application/json` header. The JSON request data should contain 4 +fields: + +- `jsonrpc: ` - set to `"2.0"` +- `id: ` - a unique identifier for the request, + generated by the client. Typically a string or number, though null is + technically allowed but not advised +- `method: ` - a string containing the method to be invoked +- `params: ` - a JSON array of ordered parameter values + +Example using curl: + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getBalance", + "params": [ + "83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri" + ] + } +' +``` + +The response output will be a JSON object with the following fields: + +- `jsonrpc: ` - matching the request specification +- `id: ` - matching the request identifier +- `result: ` - requested data or success + confirmation + +Requests can be sent in batches by sending an array of JSON-RPC request objects +as the data for a single POST. + +### Example Request + +The commitment parameter should be included as the last element in the `params` +array: + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "getBalance", + "params": [ + "83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri", + { + "commitment": "finalized" + } + ] + } +' +``` + +## Definitions + +- Hash: A SHA-256 hash of a chunk of data. +- Pubkey: The public key of a Ed25519 key-pair. +- Transaction: A list of Solana instructions signed by a client keypair to + authorize those actions. +- Signature: An Ed25519 signature of transaction's payload data including + instructions. This can be used to identify transactions. + +## Health Check + +Although not a JSON RPC API, a `GET /health` at the RPC HTTP Endpoint provides a +health-check mechanism for use by load balancers or other network +infrastructure. This request will always return a HTTP 200 OK response with a +body of "ok", "behind" or "unknown": + +- `ok`: The node is within `HEALTH_CHECK_SLOT_DISTANCE` slots from the latest + cluster confirmed slot +- `behind { distance }`: The node is behind `distance` slots from the latest + cluster confirmed slot where `distance > HEALTH_CHECK_SLOT_DISTANCE` +- `unknown`: The node is unable to determine where it stands in relation to the + cluster diff --git a/docs/locales/uk/rpc/http/isBlockhashValid.mdx b/docs/locales/uk/rpc/http/isBlockhashValid.mdx new file mode 100644 index 000000000..c9e951f67 --- /dev/null +++ b/docs/locales/uk/rpc/http/isBlockhashValid.mdx @@ -0,0 +1,84 @@ +--- +sidebarLabel: isBlockhashValid +title: isBlockhashValid RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/isBlockhashValid +--- + +Returns whether a blockhash is still valid or not + + + This method is only available in `solana-core` v1.9 or newer. Please use + [getFeeCalculatorForBlockhash](/docs/rpc/http/getFeeCalculatorForBlockhash) + for `solana-core` v1.8 and below. + + + + + + +### Parameters + + + the blockhash of the block to evaluate, as base-58 encoded string + + + + +Configuration object containing the following fields: + + + + + The minimum slot that the request can be evaluated at + + + + +### Result + +`` - `true` if the blockhash is still valid + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "id":45, + "jsonrpc":"2.0", + "method":"isBlockhashValid", + "params":[ + "J7rBdM6AecPDEZp8aPq5iPSNKVkU5Q76F3oAV4eW5wsW", + {"commitment":"processed"} + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 2483 + }, + "value": false + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/minimumLedgerSlot.mdx b/docs/locales/uk/rpc/http/minimumLedgerSlot.mdx new file mode 100644 index 000000000..d4596b0cb --- /dev/null +++ b/docs/locales/uk/rpc/http/minimumLedgerSlot.mdx @@ -0,0 +1,47 @@ +--- +sidebarLabel: minimumLedgerSlot +title: minimumLedgerSlot RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/minimumLedgerSlot +--- + +Returns the lowest slot that the node has information about in its ledger. + + + This value may increase over time if the node is configured to purge older + ledger data + + + + + + +### Parameters + +**None** + +### Result + +`u64` - Minimum ledger slot number + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0","id":1, "method":"minimumLedgerSlot"} +' +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": 1234, "id": 1 } +``` + + + diff --git a/docs/locales/uk/rpc/http/requestAirdrop.mdx b/docs/locales/uk/rpc/http/requestAirdrop.mdx new file mode 100644 index 000000000..b2ff929ad --- /dev/null +++ b/docs/locales/uk/rpc/http/requestAirdrop.mdx @@ -0,0 +1,72 @@ +--- +sidebarLabel: requestAirdrop +title: requestAirdrop RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/requestAirdrop +--- + +Requests an airdrop of lamports to a Pubkey + + + + + +### Parameters + + + Pubkey of account to receive lamports, as a base-58 encoded string + + + + lamports to airdrop, as a "u64" + + + + +Configuration object containing the following fields: + + + + + +### Result + +`` - Transaction Signature of the airdrop, as a base-58 encoded string + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", "id": 1, + "method": "requestAirdrop", + "params": [ + "83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri", + 1000000000 + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": "5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW", + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/sendTransaction.mdx b/docs/locales/uk/rpc/http/sendTransaction.mdx new file mode 100644 index 000000000..d77f578d0 --- /dev/null +++ b/docs/locales/uk/rpc/http/sendTransaction.mdx @@ -0,0 +1,125 @@ +--- +sidebarLabel: sendTransaction +title: sendTransaction RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/sendTransaction +--- + +Submits a signed transaction to the cluster for processing. + +This method does not alter the transaction in any way; it relays the transaction +created by clients to the node as-is. + +If the node's rpc service receives the transaction, this method immediately +succeeds, without waiting for any confirmations. A successful response from this +method does not guarantee the transaction is processed or confirmed by the +cluster. + +While the rpc service will reasonably retry to submit it, the transaction could +be rejected if transaction's `recent_blockhash` expires before it lands. + +Use [`getSignatureStatuses`](/docs/rpc/http/getSignatureStatuses) to ensure a +transaction is processed and confirmed. + +Before submitting, the following preflight checks are performed: + +1. The transaction signatures are verified +2. The transaction is simulated against the bank slot specified by the preflight + commitment. On failure an error will be returned. Preflight checks may be + disabled if desired. It is recommended to specify the same commitment and + preflight commitment to avoid confusing behavior. + +The returned signature is the first signature in the transaction, which is used +to identify the transaction +([transaction id](/docs/terminology.md#transaction-id)). This identifier can be +easily extracted from the transaction data before submission. + + + + + +### Parameters + + + Fully-signed Transaction, as encoded string. + + + + +Configuration object containing the following optional fields: + + + +Encoding used for the transaction data. + +Values: `base58` (_slow_, **DEPRECATED**), or `base64`. + + + + + when `true`, skip the preflight transaction checks + + + + Commitment level to use for preflight. + + + + Maximum number of times for the RPC node to retry sending the transaction to + the leader. If this parameter not provided, the RPC node will retry the + transaction until it is finalized or until the blockhash expires. + + + + set the minimum slot at which to perform preflight transaction checks + + + + +### Result + +`` - First Transaction Signature embedded in the transaction, as base-58 +encoded string ([transaction id](/docs/terminology.md#transaction-id)) + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "sendTransaction", + "params": [ + "4hXTCkRzt9WyecNzV1XPgCDfGAZzQKNxLXgynz5QDuWWPSAZBZSHptvWRL3BjCvzUXRdKvHL2b7yGrRQcWyaqsaBCncVG7BFggS8w9snUts67BSh3EqKpXLUm5UMHfD7ZBe9GhARjbNQMLJ1QD3Spr6oMTBU6EhdB4RD8CP2xUxr2u3d6fos36PD98XS6oX8TQjLpsMwncs5DAMiD4nNnR8NBfyghGCWvCVifVwvA8B8TJxE1aiyiv2L429BCWfyzAme5sZW8rDb14NeCQHhZbtNqfXhcp2tAnaAT" + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": "2id3YC2jK9G5Wo2phDx4gJVAew8DcY5NAojnVuao8rkxwPYPe8cSwE5GzhEgJA2y8fVjDEo6iR6ykBvDxrTQrtpb", + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/http/simulateTransaction.mdx b/docs/locales/uk/rpc/http/simulateTransaction.mdx new file mode 100644 index 000000000..8256f7d72 --- /dev/null +++ b/docs/locales/uk/rpc/http/simulateTransaction.mdx @@ -0,0 +1,197 @@ +--- +sidebarLabel: simulateTransaction +title: simulateTransaction RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/simulateTransaction +--- + +Simulate sending a transaction + + + + + +### Parameters + + + +Transaction, as an encoded string. + + + The transaction must have a valid blockhash, but is not required to be signed. + + + + + + +Configuration object containing the following fields: + + + Commitment level to simulate the transaction at + + + + if `true` the transaction signatures will be verified (conflicts with + `replaceRecentBlockhash`) + + + + if `true` the transaction recent blockhash will be replaced with the most + recent blockhash. (conflicts with `sigVerify`) + + + + the minimum slot that the request can be evaluated at + + + + +Encoding used for the transaction data. + +Values: `base58` (_slow_, **DEPRECATED**), or `base64`. + + + + + +If `true` the response will include +[inner instructions](/docs/rpc/json-structures#inner-instructions). These inner +instructions will be `jsonParsed` where possible, otherwise `json`. + + + + + +Accounts configuration object containing the following fields: + + + An `array` of accounts to return, as base-58 encoded strings + + + + +encoding for returned Account data + + + +
+ +- `jsonParsed` encoding attempts to use program-specific state parsers to return + more human-readable and explicit account state data. +- If `jsonParsed` is requested but a + [parser cannot be found](https://github.com/solana-labs/solana/blob/cfd0a00ae2ba85a6d76757df8b4fa38ed242d185/account-decoder/src/parse_account_data.rs#L98-L100), + the field falls back to `base64` encoding, detectable when the returned + `accounts.data` field is type `string`. + +
+ +
+ +
+ +
+ +### Result + +The result will be an RpcResponse JSON object with `value` set to a JSON object +with the following fields: + +- `err: ` - Error if transaction failed, null if transaction + succeeded. + [TransactionError definitions](https://github.com/solana-labs/solana/blob/c0c60386544ec9a9ec7119229f37386d9f070523/sdk/src/transaction/error.rs#L13) +- `logs: ` - Array of log messages the transaction instructions + output during execution, null if simulation failed before the transaction was + able to execute (for example due to an invalid blockhash or signature + verification failure) +- `accounts: ` - array of accounts with the same length as the + `accounts.addresses` array in the request + - `` - if the account doesn't exist or if `err` is not null + - `` - otherwise, a JSON object containing: + - `lamports: ` - number of lamports assigned to this account, as a u64 + - `owner: ` - base-58 encoded Pubkey of the program this account has + been assigned to + - `data: <[string, encoding]|object>` - data associated with the account, + either as encoded binary data or JSON format `{: }` - + depending on encoding parameter + - `executable: ` - boolean indicating if the account contains a + program \(and is strictly read-only\) + - `rentEpoch: ` - the epoch at which this account will next owe rent, + as u64 +- `unitsConsumed: ` - The number of compute budget units consumed + during the processing of this transaction +- `returnData: ` - the most-recent return data generated by an + instruction in the transaction, with the following fields: + - `programId: ` - the program that generated the return data, as + base-58 encoded Pubkey + - `data: <[string, encoding]>` - the return data itself, as base-64 encoded + binary data +- `innerInstructions: ` - Defined only if + `innerInstructions` was set to `true`. The value is a list of + [inner instructions](/docs/rpc/json-structures#inner-instructions). + + + + + +### Code sample + +```shell +curl https://api.devnet.solana.com -s -X POST -H "Content-Type: application/json" -d ' + { + "jsonrpc": "2.0", + "id": 1, + "method": "simulateTransaction", + "params": [ + "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEDArczbMia1tLmq7zz4DinMNN0pJ1JtLdqIJPUw3YrGCzYAMHBsgN27lcgB6H2WQvFgyZuJYHa46puOQo9yQ8CVQbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCp20C7Wj2aiuk5TReAXo+VTVg8QTHjs0UjNMMKCvpzZ+ABAgEBARU=", + { + "encoding":"base64" + } + ] + } +' +``` + +### Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 218 + }, + "value": { + "err": null, + "accounts": null, + "logs": [ + "Program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri invoke [1]", + "Program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri consumed 2366 of 1400000 compute units", + "Program return: 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri KgAAAAAAAAA=", + "Program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri success" + ], + "returnData": { + "data": ["Kg==", "base64"], + "programId": "83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri" + }, + "unitsConsumed": 2366 + } + }, + "id": 1 +} +``` + + + diff --git a/docs/locales/uk/rpc/index.mdx b/docs/locales/uk/rpc/index.mdx new file mode 100644 index 000000000..8f9d69045 --- /dev/null +++ b/docs/locales/uk/rpc/index.mdx @@ -0,0 +1,99 @@ +--- +title: Solana RPC Methods & Documentation +seoTitle: "Solana RPC Methods: HTTP & Websockets" +sidebarLabel: Solana RPC Methods +sidebarSortOrder: 1 +hideTableOfContents: false +--- + +Interact with Solana nodes directly with the JSON RPC API via the HTTP and +Websocket methods. + +## Configuring State Commitment + +For preflight checks and transaction processing, Solana nodes choose which bank +state to query based on a commitment requirement set by the client. The +commitment describes how finalized a block is at that point in time. When +querying the ledger state, it's recommended to use lower levels of commitment to +report progress and higher levels to ensure the state will not be rolled back. + +In descending order of commitment (most finalized to least finalized), clients +may specify: + +- `finalized` - the node will query the most recent block confirmed by + supermajority of the cluster as having reached maximum lockout, meaning the + cluster has recognized this block as finalized +- `confirmed` - the node will query the most recent block that has been voted on + by supermajority of the cluster. + - It incorporates votes from gossip and replay. + - It does not count votes on descendants of a block, only direct votes on that + block. + - This confirmation level also upholds "optimistic confirmation" guarantees in + release 1.3 and onwards. +- `processed` - the node will query its most recent block. Note that the block + may still be skipped by the cluster. + +For processing many dependent transactions in series, it's recommended to use +`confirmed` commitment, which balances speed with rollback safety. For total +safety, it's recommended to use `finalized` commitment. + +### Default Commitment + +If commitment configuration is not provided, the node will +[default to `finalized` commitment](https://github.com/anza-xyz/agave/blob/aa0922d6845e119ba466f88497e8209d1c82febc/sdk/src/commitment_config.rs#L199-L203) + +Only methods that query bank state accept the commitment parameter. They are +indicated in the API Reference below. + +## RpcResponse Structure + +Many methods that take a commitment parameter return an RpcResponse JSON object +comprised of two parts: + +- `context` : An RpcResponseContext JSON structure including a `slot` field at + which the operation was evaluated. +- `value` : The value returned by the operation itself. + +## Parsed Responses + +Some methods support an `encoding` parameter, and can return account or +instruction data in parsed JSON format if `"encoding":"jsonParsed"` is requested +and the node has a parser for the owning program. Solana nodes currently support +JSON parsing for the following native and SPL programs: + +| Program | Account State | Instructions | +| ---------------------------- | ------------- | ------------ | +| Address Lookup | v1.15.0 | v1.15.0 | +| BPF Loader | n/a | stable | +| BPF Upgradeable Loader | stable | stable | +| Config | stable | | +| SPL Associated Token Account | n/a | stable | +| SPL Memo | n/a | stable | +| SPL Token | stable | stable | +| SPL Token 2022 | stable | stable | +| Stake | stable | stable | +| Vote | stable | stable | + +The list of account parsers can be found +[here](https://github.com/solana-labs/solana/blob/master/account-decoder/src/parse_account_data.rs), +and instruction parsers +[here](https://github.com/solana-labs/solana/blob/master/transaction-status/src/parse_instruction.rs). + +## Filter criteria + +Some methods support providing a `filters` object to enable pre-filtering the +data returned within the RpcResponse JSON object. The following filters exist: + +- `memcmp: object` - compares a provided series of bytes with program account + data at a particular offset. Fields: + + - `offset: usize` - offset into program account data to start comparison + - `bytes: string` - data to match, as encoded string + - `encoding: string` - encoding for filter `bytes` data, either "base58" or + "base64". Data is limited in size to 128 or fewer decoded bytes.
+ **NEW: This field, and base64 support generally, is only available in + solana-core v1.14.0 or newer. Please omit when querying nodes on earlier + versions** + +- `dataSize: u64` - compares the program account data length with the provided + data size diff --git a/docs/locales/uk/rpc/json-structures.mdx b/docs/locales/uk/rpc/json-structures.mdx new file mode 100644 index 000000000..0855dc189 --- /dev/null +++ b/docs/locales/uk/rpc/json-structures.mdx @@ -0,0 +1,110 @@ +--- +title: Common JSON Data Structures for Solana RPC Methods +sidebarLabel: Data Structures as JSON +sidebarSortOrder: -1 +hideTableOfContents: false +--- + +Various Solana RPC methods will return more complex responses as structured JSON +objects, filled with specific keyed values. + +The most common of these JSON data structures include: + +- [transactions](#transactions) +- [inner instructions](#inner-instructions) +- [token balances](#token-balances) + +## Transactions + +Transactions are quite different from those on other blockchains. Be sure to +review [Anatomy of a Transaction](/docs/core/transactions.md) to learn about +transactions on Solana. + +The JSON structure of a transaction is defined as follows: + +- `signatures: ` - A list of base-58 encoded signatures applied + to the transaction. The list is always of length + `message.header.numRequiredSignatures` and not empty. The signature at index + `i` corresponds to the public key at index `i` in `message.accountKeys`. The + first one is used as the + [transaction id](/docs/terminology.md#transaction-id). +- `message: ` - Defines the content of the transaction. + - `accountKeys: ` - List of base-58 encoded public keys used by + the transaction, including by the instructions and for signatures. The first + `message.header.numRequiredSignatures` public keys must sign the + transaction. + - `header: ` - Details the account types and signatures required by + the transaction. + - `numRequiredSignatures: ` - The total number of signatures + required to make the transaction valid. The signatures must match the + first `numRequiredSignatures` of `message.accountKeys`. + - `numReadonlySignedAccounts: ` - The last + `numReadonlySignedAccounts` of the signed keys are read-only accounts. + Programs may process multiple transactions that load read-only accounts + within a single PoH entry, but are not permitted to credit or debit + lamports or modify account data. Transactions targeting the same + read-write account are evaluated sequentially. + - `numReadonlyUnsignedAccounts: ` - The last + `numReadonlyUnsignedAccounts` of the unsigned keys are read-only accounts. + - `recentBlockhash: ` - A base-58 encoded hash of a recent block in + the ledger used to prevent transaction duplication and to give transactions + lifetimes. + - `instructions: ` - List of program instructions that will be + executed in sequence and committed in one atomic transaction if all succeed. + - `programIdIndex: ` - Index into the `message.accountKeys` array + indicating the program account that executes this instruction. + - `accounts: ` - List of ordered indices into the + `message.accountKeys` array indicating which accounts to pass to the + program. + - `data: ` - The program input data encoded in a base-58 string. + - `addressTableLookups: ` - List of address table + lookups used by a transaction to dynamically load addresses from on-chain + address lookup tables. Undefined if `maxSupportedTransactionVersion` is not + set. + - `accountKey: ` - base-58 encoded public key for an address lookup + table account. + - `writableIndexes: ` - List of indices used to load + addresses of writable accounts from a lookup table. + - `readonlyIndexes: ` - List of indices used to load + addresses of readonly accounts from a lookup table. + +## Inner Instructions + +The Solana runtime records the cross-program instructions that are invoked +during transaction processing and makes these available for greater transparency +of what was executed on-chain per transaction instruction. Invoked instructions +are grouped by the originating transaction instruction and are listed in order +of processing. + +The JSON structure of inner instructions is defined as a list of objects in the +following structure: + +- `index: number` - Index of the transaction instruction from which the inner + instruction(s) originated +- `instructions: ` - Ordered list of inner program instructions + that were invoked during a single transaction instruction. + - `programIdIndex: ` - Index into the `message.accountKeys` array + indicating the program account that executes this instruction. + - `accounts: ` - List of ordered indices into the + `message.accountKeys` array indicating which accounts to pass to the + program. + - `data: ` - The program input data encoded in a base-58 string. + +## Token Balances + +The JSON structure of token balances is defined as a list of objects in the +following structure: + +- `accountIndex: ` - Index of the account in which the token balance is + provided for. +- `mint: ` - Pubkey of the token's mint. +- `owner: ` - Pubkey of token balance's owner. +- `programId: ` - Pubkey of the Token program that owns the + account. +- `uiTokenAmount: ` - + - `amount: ` - Raw amount of tokens as a string, ignoring decimals. + - `decimals: ` - Number of decimals configured for token's mint. + - `uiAmount: ` - Token amount as a float, accounting for + decimals. **DEPRECATED** + - `uiAmountString: ` - Token amount as a string, accounting for + decimals. diff --git a/docs/locales/uk/rpc/websocket/accountSubscribe.mdx b/docs/locales/uk/rpc/websocket/accountSubscribe.mdx new file mode 100644 index 000000000..df731376f --- /dev/null +++ b/docs/locales/uk/rpc/websocket/accountSubscribe.mdx @@ -0,0 +1,160 @@ +--- +sidebarLabel: accountSubscribe +title: accountSubscribe RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/accountSubscribe +--- + +Subscribe to an account to receive notifications when the lamports or data for a +given account public key changes + + + + + +### Parameters + + + Account Pubkey, as base-58 encoded string + + + + +Configuration object containing the following fields: + + + + + +Encoding format for Account data + + + +
+ +- `base58` is slow. +- `jsonParsed` encoding attempts to use program-specific state parsers to return + more human-readable and explicit account state data +- If `jsonParsed` is requested but a parser cannot be found, the field falls + back to binary encoding, detectable when the `data`field is type`string`. + +
+ +
+ +
+ +### Result + +`` - Subscription id \(needed to unsubscribe\) + +
+ + + +### Code sample + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "accountSubscribe", + "params": [ + "CM78CPUeXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNH12", + { + "encoding": "jsonParsed", + "commitment": "finalized" + } + ] +} +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": 23784, "id": 1 } +``` + + +
+ +#### Notification Format: + +The notification format is the same as seen in the +[getAccountInfo](/docs/rpc/http/getAccountInfo) RPC HTTP method. + +Base58 encoding: + +```json +{ + "jsonrpc": "2.0", + "method": "accountNotification", + "params": { + "result": { + "context": { + "slot": 5199307 + }, + "value": { + "data": [ + "11116bv5nS2h3y12kD1yUKeMZvGcKLSjQgX6BeV7u1FrjeJcKfsHPXHRDEHrBesJhZyqnnq9qJeUuF7WHxiuLuL5twc38w2TXNLxnDbjmuR", + "base58" + ], + "executable": false, + "lamports": 33594, + "owner": "11111111111111111111111111111111", + "rentEpoch": 635, + "space": 80 + } + }, + "subscription": 23784 + } +} +``` + +Parsed-JSON encoding: + +```json +{ + "jsonrpc": "2.0", + "method": "accountNotification", + "params": { + "result": { + "context": { + "slot": 5199307 + }, + "value": { + "data": { + "program": "nonce", + "parsed": { + "type": "initialized", + "info": { + "authority": "Bbqg1M4YVVfbhEzwA9SpC9FhsaG83YMTYoR4a8oTDLX", + "blockhash": "LUaQTmM7WbMRiATdMMHaRGakPtCkc2GHtH57STKXs6k", + "feeCalculator": { + "lamportsPerSignature": 5000 + } + } + } + }, + "executable": false, + "lamports": 33594, + "owner": "11111111111111111111111111111111", + "rentEpoch": 635, + "space": 80 + } + }, + "subscription": 23784 + } +} +``` diff --git a/docs/locales/uk/rpc/websocket/accountUnsubscribe.mdx b/docs/locales/uk/rpc/websocket/accountUnsubscribe.mdx new file mode 100644 index 000000000..f46399941 --- /dev/null +++ b/docs/locales/uk/rpc/websocket/accountUnsubscribe.mdx @@ -0,0 +1,47 @@ +--- +sidebarLabel: accountUnsubscribe +title: accountUnsubscribe RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/accountUnsubscribe +--- + +Unsubscribe from account change notifications + + + + + +### Parameters + + + id of the account Subscription to cancel + + +### Result + +`` - unsubscribe success message + + + + + +### Code sample + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "accountUnsubscribe", + "params": [0] +} +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": true, "id": 1 } +``` + + + diff --git a/docs/locales/uk/rpc/websocket/blockSubscribe.mdx b/docs/locales/uk/rpc/websocket/blockSubscribe.mdx new file mode 100644 index 000000000..f40659ffa --- /dev/null +++ b/docs/locales/uk/rpc/websocket/blockSubscribe.mdx @@ -0,0 +1,386 @@ +--- +sidebarLabel: blockSubscribe +title: blockSubscribe RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/blockSubscribe +--- + +Subscribe to receive notification anytime a new block is `confirmed` or +`finalized`. + + + This subscription is considered **unstable** and is only available if the + validator was started with the `--rpc-pubsub-enable-block-subscription` flag. + The format of this subscription may change in the future. + + + + + + +### Parameters + + + +filter criteria for the logs to receive results by account type; currently +supported: + + + `all` - include all transactions in block + + + + +A JSON object with the following field: + +- `mentionsAccountOrProgram: ` - return only transactions that mention + the provided public key (as base-58 encoded string). If no mentions in a given + block, then no notification will be sent. + + + + + + + +Configuration object containing the following fields: + + + +- `processed` is not supported. + + + + + +encoding format for each returned Transaction + + + +
+ +- `jsonParsed` attempts to use program-specific instruction parsers to return + more human-readable and explicit data in the + `transaction.message.instructions` list. +- If `jsonParsed` is requested but a parser cannot be found, the instruction + falls back to regular JSON encoding (`accounts`, `data`, and `programIdIndex` + fields). + +
+ +
+ + + +level of transaction detail to return + + + +
+ +- If `accounts` are requested, transaction details only include signatures and + an annotated list of accounts in each transaction. +- Transaction metadata is limited to only: fee, err, pre_balances, + post_balances, pre_token_balances, and post_token_balances. + +
+ +
+ + + +the max transaction version to return in responses. + +
+ +- If the requested block contains a transaction with a higher version, an error + will be returned. +- If this parameter is omitted, only legacy transactions will be returned, and a + block containing any versioned transaction will prompt the error. + +
+ +
+ + + whether to populate the `rewards` array. If parameter not provided, the + default includes rewards. + + +
+ +### Result + +`integer` - subscription id \(needed to unsubscribe\) + +
+ + + +### Code sample + +```json +{ + "jsonrpc": "2.0", + "id": "1", + "method": "blockSubscribe", + "params": ["all"] +} +``` + +```json +{ + "jsonrpc": "2.0", + "id": "1", + "method": "blockSubscribe", + "params": [ + { + "mentionsAccountOrProgram": "LieKvPRE8XeX3Y2xVNHjKlpAScD12lYySBVQ4HqoJ5op" + }, + { + "commitment": "confirmed", + "encoding": "base64", + "showRewards": true, + "transactionDetails": "full" + } + ] +} +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": 0, "id": 1 } +``` + + +
+ +#### Notification Format: + +The notification will be an object with the following fields: + +- `slot: ` - The corresponding slot. +- `err: ` - Error if something went wrong publishing the + notification otherwise null. +- `block: ` - A block object as seen in the + [getBlock](/docs/rpc/http/getblock) RPC HTTP method. + +```json +{ + "jsonrpc": "2.0", + "method": "blockNotification", + "params": { + "result": { + "context": { + "slot": 112301554 + }, + "value": { + "slot": 112301554, + "block": { + "previousBlockhash": "GJp125YAN4ufCSUvZJVdCyWQJ7RPWMmwxoyUQySydZA", + "blockhash": "6ojMHjctdqfB55JDpEpqfHnP96fiaHEcvzEQ2NNcxzHP", + "parentSlot": 112301553, + "transactions": [ + { + "transaction": [ + "OpltwoUvWxYi1P2U8vbIdE/aPntjYo5Aa0VQ2JJyeJE2g9Vvxk8dDGgFMruYfDu8/IfUWb0REppTe7IpAuuLRgIBAAkWnj4KHRpEWWW7gvO1c0BHy06wZi2g7/DLqpEtkRsThAXIdBbhXCLvltw50ZnjDx2hzw74NVn49kmpYj2VZHQJoeJoYJqaKcvuxCi/2i4yywedcVNDWkM84Iuw+cEn9/ROCrXY4qBFI9dveEERQ1c4kdU46xjxj9Vi+QXkb2Kx45QFVkG4Y7HHsoS6WNUiw2m4ffnMNnOVdF9tJht7oeuEfDMuUEaO7l9JeUxppCvrGk3CP45saO51gkwVYEgKzhpKjCx3rgsYxNR81fY4hnUQXSbbc2Y55FkwgRBpVvQK7/+clR4Gjhd3L4y+OtPl7QF93Akg1LaU9wRMs5nvfDFlggqI9PqJl+IvVWrNRdBbPS8LIIhcwbRTkSbqlJQWxYg3Bo2CTVbw7rt1ZubuHWWp0mD/UJpLXGm2JprWTePNULzHu67sfqaWF99LwmwjTyYEkqkRt1T0Je5VzHgJs0N5jY4iIU9K3lMqvrKOIn/2zEMZ+ol2gdgjshx+sphIyhw65F3J/Dbzk04LLkK+CULmN571Y+hFlXF2ke0BIuUG6AUF+4214Cu7FXnqo3rkxEHDZAk0lRrAJ8X/Z+iwuwI5cgbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpDLAp8axcEkaQkLDKRoWxqp8XLNZSKial7Rk+ELAVVKWoWLRXRZ+OIggu0OzMExvVLE5VHqy71FNHq4gGitkiKYNFWSLIE4qGfdFLZXy/6hwS+wq9ewjikCpd//C9BcCL7Wl0iQdUslxNVCBZHnCoPYih9JXvGefOb9WWnjGy14sG9j70+RSVx6BlkFELWwFvIlWR/tHn3EhHAuL0inS2pwX7ZQTAU6gDVaoqbR2EiJ47cKoPycBNvHLoKxoY9AZaBjPl6q8SKQJSFyFd9n44opAgI6zMTjYF/8Ok4VpXEESp3QaoUyTI9sOJ6oFP6f4dwnvQelgXS+AEfAsHsKXxGAIUDQENAgMEBQAGBwgIDg8IBJCER3QXl1AVDBADCQoOAAQLERITDAjb7ugh3gOuTy==", + "base64" + ], + "meta": { + "err": null, + "status": { + "Ok": null + }, + "fee": 5000, + "preBalances": [ + 1758510880, 2067120, 1566000, 1461600, 2039280, 2039280, + 1900080, 1865280, 0, 3680844220, 2039280 + ], + "postBalances": [ + 1758505880, 2067120, 1566000, 1461600, 2039280, 2039280, + 1900080, 1865280, 0, 3680844220, 2039280 + ], + "innerInstructions": [ + { + "index": 0, + "instructions": [ + { + "programIdIndex": 13, + "accounts": [1, 15, 3, 4, 2, 14], + "data": "21TeLgZXNbtHXVBzCaiRmH" + }, + { + "programIdIndex": 14, + "accounts": [3, 4, 1], + "data": "6qfC8ic7Aq99" + }, + { + "programIdIndex": 13, + "accounts": [1, 15, 3, 5, 2, 14], + "data": "21TeLgZXNbsn4QEpaSEr3q" + }, + { + "programIdIndex": 14, + "accounts": [3, 5, 1], + "data": "6LC7BYyxhFRh" + } + ] + }, + { + "index": 1, + "instructions": [ + { + "programIdIndex": 14, + "accounts": [4, 3, 0], + "data": "7aUiLHFjSVdZ" + }, + { + "programIdIndex": 19, + "accounts": [17, 18, 16, 9, 11, 12, 14], + "data": "8kvZyjATKQWYxaKR1qD53V" + }, + { + "programIdIndex": 14, + "accounts": [9, 11, 18], + "data": "6qfC8ic7Aq99" + } + ] + } + ], + "logMessages": [ + "Program QMNeHCGYnLVDn1icRAfQZpjPLBNkfGbSKRB83G5d8KB invoke [1]", + "Program QMWoBmAyJLAsA1Lh9ugMTw2gciTihncciphzdNzdZYV invoke [2]" + ], + "preTokenBalances": [ + { + "accountIndex": 4, + "mint": "iouQcQBAiEXe6cKLS85zmZxUqaCqBdeHFpqKoSz615u", + "uiTokenAmount": { + "uiAmount": null, + "decimals": 6, + "amount": "0", + "uiAmountString": "0" + }, + "owner": "LieKvPRE8XeX3Y2xVNHjKlpAScD12lYySBVQ4HqoJ5op", + "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "accountIndex": 5, + "mint": "iouQcQBAiEXe6cKLS85zmZxUqaCqBdeHFpqKoSz615u", + "uiTokenAmount": { + "uiAmount": 11513.0679, + "decimals": 6, + "amount": "11513067900", + "uiAmountString": "11513.0679" + }, + "owner": "rXhAofQCT7NN9TUqigyEAUzV1uLL4boeD8CRkNBSkYk", + "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "accountIndex": 10, + "mint": "Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1", + "uiTokenAmount": { + "uiAmount": null, + "decimals": 6, + "amount": "0", + "uiAmountString": "0" + }, + "owner": "CL9wkGFT3SZRRNa9dgaovuRV7jrVVigBUZ6DjcgySsCU", + "programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" + }, + { + "accountIndex": 11, + "mint": "Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1", + "uiTokenAmount": { + "uiAmount": 15138.514093, + "decimals": 6, + "amount": "15138514093", + "uiAmountString": "15138.514093" + }, + "owner": "LieKvPRE8XeX3Y2xVNHjKlpAScD12lYySBVQ4HqoJ5op", + "programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" + } + ], + "postTokenBalances": [ + { + "accountIndex": 4, + "mint": "iouQcQBAiEXe6cKLS85zmZxUqaCqBdeHFpqKoSz615u", + "uiTokenAmount": { + "uiAmount": null, + "decimals": 6, + "amount": "0", + "uiAmountString": "0" + }, + "owner": "LieKvPRE8XeX3Y2xVNHjKlpAScD12lYySBVQ4HqoJ5op", + "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "accountIndex": 5, + "mint": "iouQcQBAiEXe6cKLS85zmZxUqaCqBdeHFpqKoSz615u", + "uiTokenAmount": { + "uiAmount": 11513.103028, + "decimals": 6, + "amount": "11513103028", + "uiAmountString": "11513.103028" + }, + "owner": "rXhAofQCT7NN9TUqigyEAUzV1uLL4boeD8CRkNBSkYk", + "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "accountIndex": 10, + "mint": "Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1", + "uiTokenAmount": { + "uiAmount": null, + "decimals": 6, + "amount": "0", + "uiAmountString": "0" + }, + "owner": "CL9wkGFT3SZRRNa9dgaovuRV7jrVVigBUZ6DjcgySsCU", + "programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" + }, + { + "accountIndex": 11, + "mint": "Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1", + "uiTokenAmount": { + "uiAmount": 15489.767829, + "decimals": 6, + "amount": "15489767829", + "uiAmountString": "15489.767829" + }, + "owner": "BeiHVPRE8XeX3Y2xVNrSsTpAScH94nYySBVQ4HqgN9at", + "programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" + } + ], + "rewards": [] + } + } + ], + "blockTime": 1639926816, + "blockHeight": 101210751 + }, + "err": null + } + }, + "subscription": 14 + } +} +``` diff --git a/docs/locales/uk/rpc/websocket/blockUnsubscribe.mdx b/docs/locales/uk/rpc/websocket/blockUnsubscribe.mdx new file mode 100644 index 000000000..a1dd8b893 --- /dev/null +++ b/docs/locales/uk/rpc/websocket/blockUnsubscribe.mdx @@ -0,0 +1,47 @@ +--- +sidebarLabel: blockUnsubscribe +title: blockUnsubscribe RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/blockUnsubscribe +--- + +Unsubscribe from block notifications + + + + + +### Parameters + + + subscription id to cancel + + +### Result + +`` - unsubscribe success message + + + + + +### Code sample + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "blockUnsubscribe", + "params": [0] +} +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": true, "id": 1 } +``` + + + diff --git a/docs/locales/uk/rpc/websocket/index.mdx b/docs/locales/uk/rpc/websocket/index.mdx new file mode 100644 index 000000000..bfee36c14 --- /dev/null +++ b/docs/locales/uk/rpc/websocket/index.mdx @@ -0,0 +1,23 @@ +--- +title: Solana RPC Websocket Methods +seoTitle: Solana RPC Websocket Methods +sidebarLabel: Websocket Methods +sidebarSortOrder: 2 +hideTableOfContents: false +--- + +After connecting to the RPC PubSub websocket at `ws://
/`: + +- Submit subscription requests to the websocket using the methods below +- Multiple subscriptions may be active at once +- Many subscriptions take the optional + [`commitment` parameter](/docs/rpc/index.mdx#configuring-state-commitment), + defining how finalized a change should be to trigger a notification. For + subscriptions, if commitment is unspecified, the default value is `finalized`. + +## RPC PubSub WebSocket Endpoint + +Default port: `8900` + +- ws://localhost:8900 +- http://192.168.1.88:8900 diff --git a/docs/locales/uk/rpc/websocket/logsSubscribe.mdx b/docs/locales/uk/rpc/websocket/logsSubscribe.mdx new file mode 100644 index 000000000..17190b77e --- /dev/null +++ b/docs/locales/uk/rpc/websocket/logsSubscribe.mdx @@ -0,0 +1,138 @@ +--- +sidebarLabel: logsSubscribe +title: logsSubscribe RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/logsSubscribe +--- + +Subscribe to transaction logging + + + + + +### Parameters + + + filter criteria for the logs to receive results by account type. The following filters types are currently supported: + + + +A string with one of the following values: + +- `all` - subscribe to all transactions except for simple vote transactions +- `allWithVotes` - subscribe to all transactions, including simple vote + transactions + + + + + +An object with the following field: + +- `mentions: [ ]` - array containing a single Pubkey (as base-58 + encoded string); if present, subscribe to only transactions mentioning this + address + + + The `mentions` field currently [only supports + one](https://github.com/solana-labs/solana/blob/master/rpc/src/rpc_pubsub.rs#L481) + Pubkey string per method call. Listing additional addresses will result in an + error. + + + + + + + + +Configuration object containing the following fields: + + + + + +### Result + +`` - Subscription id \(needed to unsubscribe\) + + + + + +### Code sample + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "logsSubscribe", + "params": [ + { + "mentions": [ "11111111111111111111111111111111" ] + }, + { + "commitment": "finalized" + } + ] +} +{ + "jsonrpc": "2.0", + "id": 1, + "method": "logsSubscribe", + "params": [ "all" ] +} +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": 24040, "id": 1 } +``` + + + + +#### Notification Format: + +The notification will be an RpcResponse JSON object with value equal to: + +- `signature: ` - The transaction signature base58 encoded. +- `err: ` - Error if transaction failed, null if transaction + succeeded. + [TransactionError definitions](https://github.com/solana-labs/solana/blob/c0c60386544ec9a9ec7119229f37386d9f070523/sdk/src/transaction/error.rs#L13) +- `logs: ` - Array of log messages the transaction instructions + output during execution, null if simulation failed before the transaction was + able to execute (for example due to an invalid blockhash or signature + verification failure) + +Example: + +```json +{ + "jsonrpc": "2.0", + "method": "logsNotification", + "params": { + "result": { + "context": { + "slot": 5208469 + }, + "value": { + "signature": "5h6xBEauJ3PK6SWCZ1PGjBvj8vDdWG3KpwATGy1ARAXFSDwt8GFXM7W5Ncn16wmqokgpiKRLuS83KUxyZyv2sUYv", + "err": null, + "logs": [ + "SBF program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri success" + ] + } + }, + "subscription": 24040 + } +} +``` diff --git a/docs/locales/uk/rpc/websocket/logsUnsubscribe.mdx b/docs/locales/uk/rpc/websocket/logsUnsubscribe.mdx new file mode 100644 index 000000000..a98d9da0f --- /dev/null +++ b/docs/locales/uk/rpc/websocket/logsUnsubscribe.mdx @@ -0,0 +1,47 @@ +--- +sidebarLabel: logsUnsubscribe +title: logsUnsubscribe RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/logsUnsubscribe +--- + +Unsubscribe from transaction logging + + + + + +### Parameters + + + subscription id to cancel + + +### Result + +`` - unsubscribe success message + + + + + +### Code sample + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "logsUnsubscribe", + "params": [0] +} +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": true, "id": 1 } +``` + + + diff --git a/docs/locales/uk/rpc/websocket/programSubscribe.mdx b/docs/locales/uk/rpc/websocket/programSubscribe.mdx new file mode 100644 index 000000000..377ef738b --- /dev/null +++ b/docs/locales/uk/rpc/websocket/programSubscribe.mdx @@ -0,0 +1,211 @@ +--- +sidebarLabel: programSubscribe +title: programSubscribe RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/programSubscribe +--- + +Subscribe to a program to receive notifications when the lamports or data for an +account owned by the given program changes + + + + + +### Parameters + + + +Pubkey of the `program_id`, as base-58 encoded string + + + + + +Configuration object containing the following fields: + + + + + +filter results using various filter objects + + + The resultant account must meet **ALL** filter criteria to be included in the + returned results + + + + + + +Encoding format for Account data + + + +
+ +- `base58` is slow. +- `jsonParsed` encoding attempts to use program-specific state parsers to return + more human-readable and explicit account state data. +- If `jsonParsed` is requested but a parser cannot be found, the field falls + back to `base64` encoding, detectable when the `data` field is type `string`. + +
+ +
+ +
+ +### Result + +`` - Subscription id \(needed to unsubscribe\) + +
+ + + +### Code sample + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "programSubscribe", + "params": [ + "11111111111111111111111111111111", + { + "encoding": "base64", + "commitment": "finalized" + } + ] +} +{ + "jsonrpc": "2.0", + "id": 1, + "method": "programSubscribe", + "params": [ + "11111111111111111111111111111111", + { + "encoding": "jsonParsed" + } + ] +} +{ + "jsonrpc": "2.0", + "id": 1, + "method": "programSubscribe", + "params": [ + "11111111111111111111111111111111", + { + "encoding": "base64", + "filters": [ + { + "dataSize": 80 + } + ] + } + ] +} +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": 24040, "id": 1 } +``` + + +
+ +#### Notification format + +The notification format is a single program account object as seen in the +[getProgramAccounts](/docs/rpc/http/getprogramaccounts) RPC HTTP method. + +Base58 encoding: + +```json +{ + "jsonrpc": "2.0", + "method": "programNotification", + "params": { + "result": { + "context": { + "slot": 5208469 + }, + "value": { + "pubkey": "H4vnBqifaSACnKa7acsxstsY1iV1bvJNxsCY7enrd1hq", + "account": { + "data": [ + "11116bv5nS2h3y12kD1yUKeMZvGcKLSjQgX6BeV7u1FrjeJcKfsHPXHRDEHrBesJhZyqnnq9qJeUuF7WHxiuLuL5twc38w2TXNLxnDbjmuR", + "base58" + ], + "executable": false, + "lamports": 33594, + "owner": "11111111111111111111111111111111", + "rentEpoch": 636, + "space": 80 + } + } + }, + "subscription": 24040 + } +} +``` + +Parsed-JSON encoding: + +```json +{ + "jsonrpc": "2.0", + "method": "programNotification", + "params": { + "result": { + "context": { + "slot": 5208469 + }, + "value": { + "pubkey": "H4vnBqifaSACnKa7acsxstsY1iV1bvJNxsCY7enrd1hq", + "account": { + "data": { + "program": "nonce", + "parsed": { + "type": "initialized", + "info": { + "authority": "Bbqg1M4YVVfbhEzwA9SpC9FhsaG83YMTYoR4a8oTDLX", + "blockhash": "LUaQTmM7WbMRiATdMMHaRGakPtCkc2GHtH57STKXs6k", + "feeCalculator": { + "lamportsPerSignature": 5000 + } + } + } + }, + "executable": false, + "lamports": 33594, + "owner": "11111111111111111111111111111111", + "rentEpoch": 636, + "space": 80 + } + } + }, + "subscription": 24040 + } +} +``` diff --git a/docs/locales/uk/rpc/websocket/programUnsubscribe.mdx b/docs/locales/uk/rpc/websocket/programUnsubscribe.mdx new file mode 100644 index 000000000..e548ddf88 --- /dev/null +++ b/docs/locales/uk/rpc/websocket/programUnsubscribe.mdx @@ -0,0 +1,47 @@ +--- +sidebarLabel: programUnsubscribe +title: programUnsubscribe RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/programUnsubscribe +--- + +Unsubscribe from program-owned account change notifications + + + + + +### Parameters + + + id of account Subscription to cancel + + +### Result + +`` - unsubscribe success message + + + + + +### Code sample + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "programUnsubscribe", + "params": [0] +} +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": true, "id": 1 } +``` + + + diff --git a/docs/locales/uk/rpc/websocket/rootSubscribe.mdx b/docs/locales/uk/rpc/websocket/rootSubscribe.mdx new file mode 100644 index 000000000..16bf8b689 --- /dev/null +++ b/docs/locales/uk/rpc/websocket/rootSubscribe.mdx @@ -0,0 +1,55 @@ +--- +sidebarLabel: rootSubscribe +title: rootSubscribe RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/rootSubscribe +--- + +Subscribe to receive notification anytime a new root is set by the validator. + + + + + +### Parameters + +**None** + +### Result + +`integer` - subscription id \(needed to unsubscribe\) + + + + + +### Code sample + +```json +{ "jsonrpc": "2.0", "id": 1, "method": "rootSubscribe" } +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": 0, "id": 1 } +``` + + + + +#### Notification Format: + +The result is the latest root slot number. + +```json +{ + "jsonrpc": "2.0", + "method": "rootNotification", + "params": { + "result": 42, + "subscription": 0 + } +} +``` diff --git a/docs/locales/uk/rpc/websocket/rootUnsubscribe.mdx b/docs/locales/uk/rpc/websocket/rootUnsubscribe.mdx new file mode 100644 index 000000000..4f8068929 --- /dev/null +++ b/docs/locales/uk/rpc/websocket/rootUnsubscribe.mdx @@ -0,0 +1,47 @@ +--- +sidebarLabel: rootUnsubscribe +title: rootUnsubscribe RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/rootUnsubscribe +--- + +Unsubscribe from root notifications + + + + + +### Parameters + + + subscription id to cancel + + +### Result + +`` - unsubscribe success message + + + + + +### Code sample + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "rootUnsubscribe", + "params": [0] +} +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": true, "id": 1 } +``` + + + diff --git a/docs/locales/uk/rpc/websocket/signatureSubscribe.mdx b/docs/locales/uk/rpc/websocket/signatureSubscribe.mdx new file mode 100644 index 000000000..ea33dc026 --- /dev/null +++ b/docs/locales/uk/rpc/websocket/signatureSubscribe.mdx @@ -0,0 +1,149 @@ +--- +sidebarLabel: signatureSubscribe +title: signatureSubscribe RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/signatureSubscribe +--- + +Subscribe to receive a notification when the transaction with the given +signature reaches the specified commitment level. + + + This is a subscription to a single notification. It is automatically cancelled + by the server once the notification, `signatureNotification`, is sent by the + RPC. + + + + + + +### Parameters + + + +transaction signature, as base-58 encoded string + + + The transaction signature must be the first signature from the transaction + (see [transaction id](/docs/terminology.md#transaction-id) for more details). + + + + + + +Configuration object containing the following fields: + + + + + +Whether or not to subscribe for notifications when signatures are received by +the RPC, in addition to when they are processed. + + + + + +### Result + +`` - subscription id (needed to unsubscribe) + + + + + +### Code sample + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "signatureSubscribe", + "params": [ + "2EBVM6cB8vAAD93Ktr6Vd8p67XPbQzCJX47MpReuiCXJAtcjaxpvWpcg9Ege1Nr5Tk3a2GFrByT7WPBjdsTycY9b", + { + "commitment": "finalized", + "enableReceivedNotification": false + } + ] +} +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": 0, "id": 1 } +``` + + + + +#### Notification Format: + +The notification will be an RpcResponse JSON object with value containing an +object with: + +- `slot: ` - The corresponding slot. +- `value: ` - a notification value of + [`RpcSignatureResult`](https://github.com/solana-labs/solana/blob/6d28fd455b07e3557fc6c0c3ddf3ba03e3fe8482/rpc-client-api/src/response.rs#L265-L268), + resulting in either: + - when `enableReceivedNotification` is `true` and the signature is received: + the literal string + [`"receivedSignature"`](https://github.com/solana-labs/solana/blob/6d28fd455b07e3557fc6c0c3ddf3ba03e3fe8482/rpc-client-api/src/response.rs#L286-L288), + or + - when the signature is processed: `err: `: + - `null` if the transaction succeeded in being processed at the specified + commitment level, or + - a + [`TransactionError`](https://github.com/solana-labs/solana/blob/6d28fd455b07e3557fc6c0c3ddf3ba03e3fe8482/sdk/src/transaction/error.rs#L15-L164), + if the transaction failed + +#### Example responses: + +The following is an example response of a notification from a successfully +**processed** transactions: + +```json +{ + "jsonrpc": "2.0", + "method": "signatureNotification", + "params": { + "result": { + "context": { + "slot": 5207624 + }, + "value": { + "err": null + } + }, + "subscription": 24006 + } +} +``` + +The following is an example response of a notification from a successfully +**received** transaction signature: + +```json +{ + "jsonrpc": "2.0", + "method": "signatureNotification", + "params": { + "result": { + "context": { + "slot": 5207624 + }, + "value": "receivedSignature" + }, + "subscription": 24006 + } +} +``` diff --git a/docs/locales/uk/rpc/websocket/signatureUnsubscribe.mdx b/docs/locales/uk/rpc/websocket/signatureUnsubscribe.mdx new file mode 100644 index 000000000..f34ced2dd --- /dev/null +++ b/docs/locales/uk/rpc/websocket/signatureUnsubscribe.mdx @@ -0,0 +1,47 @@ +--- +sidebarLabel: signatureUnsubscribe +title: signatureUnsubscribe RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/signatureUnsubscribe +--- + +Unsubscribe from signature confirmation notification + + + + + +### Parameters + + + subscription id to cancel + + +### Result + +`` - unsubscribe success message + + + + + +### Code sample + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "signatureUnsubscribe", + "params": [0] +} +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": true, "id": 1 } +``` + + + diff --git a/docs/locales/uk/rpc/websocket/slotSubscribe.mdx b/docs/locales/uk/rpc/websocket/slotSubscribe.mdx new file mode 100644 index 000000000..e90dff657 --- /dev/null +++ b/docs/locales/uk/rpc/websocket/slotSubscribe.mdx @@ -0,0 +1,65 @@ +--- +sidebarLabel: slotSubscribe +title: slotSubscribe RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/slotSubscribe +--- + +Subscribe to receive notification anytime a slot is processed by the validator + + + + + +### Parameters + +**None** + +### Result + +`` - Subscription id \(needed to unsubscribe\) + + + + + +### Code sample + +```json +{ "jsonrpc": "2.0", "id": 1, "method": "slotSubscribe" } +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": 0, "id": 1 } +``` + + + + +#### Notification Format: + +The notification will be an object with the following fields: + +- `parent: ` - The parent slot +- `root: ` - The current root slot +- `slot: ` - The newly set slot value + +Example: + +```json +{ + "jsonrpc": "2.0", + "method": "slotNotification", + "params": { + "result": { + "parent": 75, + "root": 44, + "slot": 76 + }, + "subscription": 0 + } +} +``` diff --git a/docs/locales/uk/rpc/websocket/slotUnsubscribe.mdx b/docs/locales/uk/rpc/websocket/slotUnsubscribe.mdx new file mode 100644 index 000000000..450afc276 --- /dev/null +++ b/docs/locales/uk/rpc/websocket/slotUnsubscribe.mdx @@ -0,0 +1,47 @@ +--- +sidebarLabel: slotUnsubscribe +title: slotUnsubscribe RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/slotUnsubscribe +--- + +Unsubscribe from slot notifications + + + + + +### Parameters + + + subscription id to cancel + + +### Result + +`` - unsubscribe success message + + + + + +### Code sample + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "slotUnsubscribe", + "params": [0] +} +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": true, "id": 1 } +``` + + + diff --git a/docs/locales/uk/rpc/websocket/slotsUpdatesSubscribe.mdx b/docs/locales/uk/rpc/websocket/slotsUpdatesSubscribe.mdx new file mode 100644 index 000000000..a683a2755 --- /dev/null +++ b/docs/locales/uk/rpc/websocket/slotsUpdatesSubscribe.mdx @@ -0,0 +1,87 @@ +--- +sidebarLabel: slotsUpdatesSubscribe +title: slotsUpdatesSubscribe RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/slotsUpdatesSubscribe +--- + +Subscribe to receive a notification from the validator on a variety of updates +on every slot + + + This subscription is unstable. The format of this subscription may change in + the future, and may not always be supported. + + + + + + +### Parameters + +**None** + +### Result + +`` - Subscription id (needed to unsubscribe) + + + + + +### Code sample + +```json +{ "jsonrpc": "2.0", "id": 1, "method": "slotsUpdatesSubscribe" } +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": 0, "id": 1 } +``` + + + + +### Notification Format + +The notification will be an object with the following fields: + +- `err: ` - The error message. Only present if the update is + of type "dead". +- `parent: ` - The parent slot. Only present if the update is of + type "createdBank". +- `slot: ` - The newly updated slot +- `stats: ` - The error message. Only present if the update is + of type "frozen". An object with the following fields: + - `maxTransactionsPerEntry: `, + - `numFailedTransactions: `, + - `numSuccessfulTransactions: `, + - `numTransactionEntries: `, +- `timestamp: ` - The Unix timestamp of the update in milliseconds +- `type: ` - The update type, one of: + - "firstShredReceived" + - "completed" + - "createdBank" + - "frozen" + - "dead" + - "optimisticConfirmation" + - "root" + +```shell +{ + "jsonrpc": "2.0", + "method": "slotsUpdatesNotification", + "params": { + "result": { + "parent": 75, + "slot": 76, + "timestamp": 1625081266243, + "type": "optimisticConfirmation" + }, + "subscription": 0 + } +} +``` diff --git a/docs/locales/uk/rpc/websocket/slotsUpdatesUnsubscribe.mdx b/docs/locales/uk/rpc/websocket/slotsUpdatesUnsubscribe.mdx new file mode 100644 index 000000000..61f25e196 --- /dev/null +++ b/docs/locales/uk/rpc/websocket/slotsUpdatesUnsubscribe.mdx @@ -0,0 +1,47 @@ +--- +sidebarLabel: slotsUpdatesUnsubscribe +title: slotsUpdatesUnsubscribe RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/slotsUpdatesUnsubscribe +--- + +Unsubscribe from slot-update notifications + + + + + +### Parameters + + + subscription id to cancel + + +### Result + +`` - unsubscribe success message + + + + + +### Code sample + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "slotsUpdatesUnsubscribe", + "params": [0] +} +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": true, "id": 1 } +``` + + + diff --git a/docs/locales/uk/rpc/websocket/voteSubscribe.mdx b/docs/locales/uk/rpc/websocket/voteSubscribe.mdx new file mode 100644 index 000000000..77384856a --- /dev/null +++ b/docs/locales/uk/rpc/websocket/voteSubscribe.mdx @@ -0,0 +1,75 @@ +--- +sidebarLabel: voteSubscribe +title: voteSubscribe RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/voteSubscribe +--- + +Subscribe to receive notification anytime a new vote is observed in gossip. +These votes are pre-consensus therefore there is no guarantee these votes will +enter the ledger. + + + This subscription is unstable and only available if the validator was started + with the `--rpc-pubsub-enable-vote-subscription` flag. The format of this + subscription may change in the future. + + + + + + +### Parameters + +**None** + +### Result + +`` - subscription id (needed to unsubscribe) + + + + + +### Code sample + +```json +{ "jsonrpc": "2.0", "id": 1, "method": "voteSubscribe" } +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": 0, "id": 1 } +``` + + + + +#### Notification Format: + +The notification will be an object with the following fields: + +- `hash: ` - The vote hash +- `slots: ` - The slots covered by the vote, as an array of u64 integers +- `timestamp: ` - The timestamp of the vote +- `signature: ` - The signature of the transaction that contained this + vote +- `votePubkey: ` - The public key of the vote account, as base-58 + encoded string + +```json +{ + "jsonrpc": "2.0", + "method": "voteNotification", + "params": { + "result": { + "hash": "8Rshv2oMkPu5E4opXTRyuyBeZBqQ4S477VG26wUTFxUM", + "slots": [1, 2], + "timestamp": null + }, + "subscription": 0 + } +} +``` diff --git a/docs/locales/uk/rpc/websocket/voteUnsubscribe.mdx b/docs/locales/uk/rpc/websocket/voteUnsubscribe.mdx new file mode 100644 index 000000000..abcfe1354 --- /dev/null +++ b/docs/locales/uk/rpc/websocket/voteUnsubscribe.mdx @@ -0,0 +1,47 @@ +--- +sidebarLabel: voteUnsubscribe +title: voteUnsubscribe RPC Method +hideTableOfContents: true +altRoutes: + - /docs/rpc/voteUnsubscribe +--- + +Unsubscribe from vote notifications + + + + + +### Parameters + + + subscription id to cancel + + +### Result + +`` - unsubscribe success message + + + + + +### Code sample + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "voteUnsubscribe", + "params": [0] +} +``` + +### Response + +```json +{ "jsonrpc": "2.0", "result": true, "id": 1 } +``` + + + diff --git a/docs/locales/uk/terminology.md b/docs/locales/uk/terminology.md new file mode 100644 index 000000000..5a06d576d --- /dev/null +++ b/docs/locales/uk/terminology.md @@ -0,0 +1,575 @@ +--- +title: Терміни +description: + "Дізнайтеся основну термінологію, яка використовується в блокчейні Solana та + моделях розробки." +keywords: + - терміни + - словник + - визначення + - програмні моделі +isSkippedInNav: true +--- + +Наведені нижче терміни використовуються в документації Solana та екосистемі +розробки. + +## Обліковий запис (account) + +Запис у реєстрі Solana, який або зберігає дані, або є виконуваною програмою. + +Як і обліковий запис у традиційному банку, обліковий запис Solana може зберігати +кошти, які називаються [лампортами](#lamport). Як файл у Linux, він адресується +ключем, часто згадуваним як [публічний ключ](#public-key-pubkey) або pubkey. + +Ключ може бути одним із таких: + +- Публічний ключ ed25519 +- Адреса облікового запису, отримана програмно (32-байтне значення поза кривою + ed25519) +- Хеш публічного ключа ed25519 із рядком із 32 символів + +## Власник облікового запису (account owner) + +Адреса програми, якій належить обліковий запис. Тільки програма-власник може +змінювати обліковий запис. + +Див. також [Повноваження](#authority). + +## Застосунок (app) + +Фронтенд-застосунок, який взаємодіє з кластером Solana. + +## Повноваження (authority) + +Адреса користувача, який має певні дозволи на обліковий запис. + +Наприклад: + +- Можливість карбування нових токенів надається обліковому запису, який є + "владою карбування" токена. +- Можливість оновлювати програму надається обліковому запису, який є "владою + оновлення" програми. + +## Стан банку (bank state) + +Результат виконання всіх програм у реєстрі на певній +[висоті тікання](#tick-height). Він включає щонайменше набір усіх +[облікових записів](#account), які зберігають ненульові +[нативні токени](#native-token). + +## Блок (block) + +Неперервний набір [записів](#entry) у реєстрі, підтверджений +[голосуванням](#ledger-vote). [Лідер](#leader) створює не більше одного блоку за +[слот](#slot). + +## Блокхеш (blockhash) + +Унікальне значення ([хеш](#hash)), яке ідентифікує запис (блок). Solana обчислює +блокхеш із останнього [ідентифікатора запису](#entry-id) блоку. + +## Висота блоку (block height) + +Кількість [блоків](#block) під поточним блоком. Перший блок після +[генезис-блоку](#genesis-block) має висоту один. + +## Завантажувач BPF (BPF loader) + +Програма Solana, яка завантажує +[програми на основі BPF](/docs/uk/core/programs#berkeley-packet-filter-bpf) в +[блокчейн](#onchain-program), дозволяючи їм взаємодіяти з середовищем виконання. + +## Клієнт (client) + +Програма, яка підключається до серверної мережі Solana [кластеру](#cluster). + +## Зобов'язання (commitment) + +Міра підтвердження мережі для [блоку](#block). + +## Кластер (cluster) + +Набір [валідаторів](#validator), які підтримують єдиний [реєстр](#ledger). + +## Бюджет обчислень (compute budget) + +Максимальна кількість [обчислювальних одиниць](#compute-units), спожитих за +транзакцію. + +## Обчислювальні одиниці (compute units) + +Найменша одиниця вимірювання споживання обчислювальних ресурсів блокчейну. + +## Час підтвердження (confirmation time) + +Час, який пройшов між створенням [тікового запису](#tick) [лідером](#leader) та +створенням [підтвердженого блоку](#confirmed-block). + +## Підтверджений блок (confirmed block) + +[Блок](#block), який отримав [супербільшість](#supermajority) +[голосів реєстру](#ledger-vote). + +## Площина керування (control plane) + +Мережева структура, яка з'єднує всі [вузли](#node) [кластеру](#cluster). + +## Період охолодження (cooldown period) + +Декілька [епох](#epoch) після деактивації [ставки](#stake), протягом яких вона +поступово стає доступною для зняття. Під час цього періоду ставка вважається +"деактивованою". Докладніше: +[періоди прогріву та охолодження](https://docs.anza.xyz/implemented-proposals/staking-rewards#stake-warmup-cooldown-withdrawal). + +## Кредит (credit) + +Див. [Кредит голосування](#vote-credit). + +## Виклик між програмами (CPI) + +Виклик однієї [програми на блокчейні](#onchain-program) до іншої. Докладніше +див. [Виклик між програмами](/docs/uk/core/cpi.md). + +## Площина даних (data plane) + +Мультикаст-мережа, яка використовується для ефективної перевірки +[записів](#entry) і досягнення консенсусу. + +## Дрон (drone) + +Зовнішній сервіс, який виступає в ролі хранителя приватного ключа користувача. +Зазвичай використовується для перевірки та підпису транзакцій. + +## Запис (entry) + +Запис у [реєстрі](#ledger), який може бути або [тіком](#tick), або +[записом транзакції](#transactions-entry). + +## Ідентифікатор запису (entry id) + +Хеш ([hash](#hash)), стійкий до попереднього зображення, який є унікальним +ідентифікатором [запису](#entry). Хеш слугує доказом: + +- Генерації запису після певного проміжку часу +- Включення зазначених [транзакцій](#transaction) у запис +- Розташування запису відносно інших записів у [реєстрі](#ledger) + +Див. [Доказ історії (Proof of History)](#proof-of-history-poh). + +## Епоха (epoch) + +Проміжок часу, визначений кількістю [слотів](#slot), протягом яких діє +[розклад лідерів](#leader-schedule). + +## Обліковий запис для комісій (fee account) + +Обліковий запис у транзакції, який оплачує вартість включення транзакції до +реєстру. Це перший обліковий запис у транзакції. Він має бути оголошений як +читально-записуваний (writable), оскільки оплата транзакції зменшує баланс +облікового запису. + +## Фінальність (finality) + +Стан, коли вузли, що представляють 2/3 [ставки](#stake), мають спільний +[корінь](#root). + +## Форк (fork) + +[Реєстр](#ledger), створений на основі загальних записів, але який розійшовся у +своєму розвитку. + +## Генезис-блок (genesis block) + +Перший [блок](#block) у ланцюжку. + +## Генезис-конфігурація (genesis config) + +Файл конфігурації, який підготовлює [реєстр](#ledger) для +[генезис-блоку](#genesis-block). + +## Хеш (hash) + +Цифровий відбиток послідовності байтів. + +## Інфляція (inflation) + +Збільшення кількості токенів із часом, яке використовується для фінансування +винагород за валідацію та подальшого розвитку Solana. + +## Внутрішня інструкція (inner instruction) + +Див. [Виклик між програмами](#cross-program-invocation-cpi). + +## Інструкція (instruction) + +Виклик для запуску конкретного [обробника інструкцій](#instruction-handler) у +[програмі](#program). Інструкція також вказує, які облікові записи потрібно +прочитати або змінити, та додаткові дані, які слугують допоміжним вхідним +параметром для [обробника інструкцій](#instruction-handler). Кожна +[транзакція](#transaction) має містити принаймні одну інструкцію. + +## Обробник інструкцій (instruction handler) + +Функції [програм](#program), які обробляють [інструкції](#instruction) із +[транзакцій](#transaction). Обробник інструкцій може містити одну або кілька +[викликів між програмами](#cross-program-invocation-cpi). + +## Пара ключів (keypair) + +[Публічний ключ](#public-key-pubkey) і відповідний +[приватний ключ](#private-key), які використовуються для доступу до облікового +запису. + +## Лампорти (lamport) + +Дробова одиниця [нативного токена](#native-token) із вартістю 0.000000001 +[SOL](#sol). + +> У межах бюджету обчислень використовується кількість +> _[мікролампортів](https://github.com/solana-labs/solana/blob/ced8f6a512c61e0dd5308095ae8457add4a39e94/program-runtime/src/prioritization_fee.rs#L1-L2)_ +> для розрахунку [пріоритетної комісії](#prioritization-fee). + +## Лідер (leader) + +Роль [валідатора](#validator), який додає [записи](#entry) до +[реєстру](#ledger). + +## Розклад лідерів (leader schedule) + +Послідовність [публічних ключів](#public-key-pubkey) [валідаторів](#validator), +пов’язаних із [слотами](#slot). Кластер використовує цей розклад, щоб визначити, +який валідатор є [лідером](#leader) у певний момент часу. + +## Реєстр (ledger) + +Список [записів](#entry), що містять [транзакції](#transaction), підписані +[клієнтами](#client). Концептуально це можна простежити до +[генезис-блоку](#genesis-block), але реєстр конкретного [валідатора](#validator) +може містити лише новіші [блоки](#block), щоб зменшити обсяг зберігання, +оскільки старіші блоки не потрібні для перевірки майбутніх блоків за задумом. + +## Голос у реєстрі (ledger vote) + +[Хеш](#hash) стану [валідатора](#validator) на певній +[висоті тікання](#tick-height). Він включає підтвердження валідатора, що +[блок](#block), який він отримав, був перевірений, а також обіцянку не +голосувати за конфліктуючий [блок](#block) (тобто [форк](#fork)) протягом +певного часу, відомого як період [блокування](#lockout). + +## Легкий клієнт (light client) + +Тип [клієнта](#client), який може перевірити, що він підключений до валідного +[кластеру](#cluster). Він виконує більше перевірок реєстру, ніж +[тонкий клієнт](#thin-client), але менше, ніж [валідатор](#validator). + +## Завантажувач (loader) + +[Програма](#program) із можливістю інтерпретувати двійкове кодування інших +програм на блокчейні. + +## Блокування (lockout) + +Тривалість часу, протягом якої [валідатор](#validator) не може +[голосувати](#ledger-vote) за інший [форк](#fork). + +## Повідомлення (message) + +Структурований вміст [транзакції](#transaction), зазвичай містить заголовок, +масив адрес облікових записів, недавній [блокхеш](#blockhash) та масив +[інструкцій](#instruction). + +Докладніше про +[форматування повідомлень у транзакціях](/docs/uk/core/transactions.md#message-header). + +## Коефіцієнт Накамото (Nakamoto coefficient) + +Міра децентралізації, яка визначає найменшу кількість незалежних суб’єктів, що +можуть колективно зупинити блокчейн. Термін запропонований Балажі С. +Срінівасаном і Леландом Лі у статті +[Quantifying Decentralization](https://news.earn.com/quantifying-decentralization-e39db233c28e). + +## Нативний токен (native token) + +[Токен](#token), що використовується для відстеження роботи [вузлів](#node) у +кластері. + +## Вузол (node) + +Комп’ютер, що бере участь у [кластері](#cluster). + +## Кількість вузлів (node count) + +Кількість [валідаторів](#validator), що беруть участь у [кластері](#cluster). + +## Програма на блокчейні (onchain program) + +Виконуваний код у блокчейні Solana, який інтерпретує [інструкції](#instruction), +надіслані в кожній [транзакції](#transaction), щоб читати та змінювати облікові +записи, якими він управляє. Ці програми часто називають +"[розумними контрактами](/docs/uk/core/programs.md)" на інших блокчейнах. + +## PoH (Proof of History) + +Див. [Доказ історії (Proof of History)](#proof-of-history-poh). + +## Окуляр (point) + +Зважений [кредит](#credit) у системі винагород. У системі +[винагород валідатора](https://docs.anza.xyz/consensus/stake-delegation-and-rewards) +кількість очок, що належить [ставці](#stake), є добутком +[голосових кредитів](#vote-credit) і кількості лампортів, що були поставлені. + +## Програма (program) + +Див. [Програма на блокчейні (onchain program)](#onchain-program). + +## Програмно отриманий обліковий запис (PDA) + +Обліковий запис, підписуючою владою якого є програма, і тому він не +контролюється приватним ключем, як інші облікові записи. + +## Ідентифікатор програми (program id) + +Публічний ключ [облікового запису](#account), який містить [програму](#program). + +## Доказ історії (Proof of History, PoH) + +Стек доказів, кожен із яких підтверджує, що певні дані існували до моменту +створення доказу і що пройшов точний проміжок часу до попереднього доказу. Як і +[перевірювана функція затримки (VDF)](#verifiable-delay-function-vdf), Proof of +History може бути перевірений швидше, ніж його створення. + +## Пріоритетна комісія (prioritization fee) + +Додаткова комісія, яку користувач може вказати в інструкції бюджету обчислень, +щоб пріоритизувати свої [транзакції](#transaction). + +Пріоритетна комісія розраховується шляхом множення запитаного максимуму +обчислювальних одиниць на ціну обчислювальної одиниці (вказується в інтервалах +0.000001 лампорта за одиницю), округлену до найближчого лампорта. + +Транзакції повинні запитувати мінімальну кількість обчислювальних одиниць, +необхідних для виконання, щоб зменшити комісію. + +## Публічний ключ (public key, pubkey) + +Публічний ключ із [пари ключів](#keypair). + +## Оренда (rent) + +Комісія, яку сплачують [облікові записи](#account) і [програми](#program) за +зберігання даних у блокчейні. Якщо на рахунку недостатньо балансу для оплати +оренди, він може бути видалений. + +Див. також [звільнення від оренди](#rent-exempt). Докладніше про оренду: +[Що таке оренда?](/docs/uk/intro/rent.md). + +## Звільнення від оренди (rent exempt) + +Облікові записи, які підтримують мінімальний баланс лампортів, пропорційний +кількості даних, що зберігаються в обліковому записі. Усі нові облікові записи +зберігаються на блокчейні постійно, доки обліковий запис не буде закрито. +Неможливо створити обліковий запис, який не відповідає порогу звільнення від +оренди. + +## Корінь (root) + +[Блок](#block) або [слот](#slot), який досяг максимального +[блокування](#lockout) у [валідатора](#validator). Корінь є найвищим блоком, +який є предком усіх активних форків у валідатора. Усі предкові блоки кореня +також транзитивно є коренями. Блоки, які не є предками чи нащадками кореня, +виключаються з розгляду для консенсусу і можуть бути відкинуті. + +## Середовище виконання (runtime) + +Компонент [валідатора](#validator), відповідальний за виконання +[програм](#program). + +## Sealevel + +Паралельне середовище виконання Solana для +[програм на блокчейні](#onchain-program). + +## Шред (shred) + +Фрагмент [блоку](#block); найменша одиниця, яка передається між +[валідаторами](#validator). + +## Підпис (signature) + +64-байтний підпис ed25519, що складається з R (32 байти) і S (32 байти). Цей +підпис забезпечує відсутність можливості модифікації (мальованості). Кожна +транзакція повинна мати щонайменше один підпис для +[облікового запису комісій](#fee-account). Таким чином, перший підпис у +транзакції може використовуватися як +[ідентифікатор транзакції](#transaction-id). + +## Рівень пропуску (skip rate) + +Відсоток [пропущених слотів](#skipped-slot) від загальної кількості слотів +лідера в поточній епосі. Ця метрика може бути оманливою через високу +варіативність після межі епохи, коли вибірка невелика, а також для валідаторів +із малою кількістю слотів лідера. Однак вона може бути корисною для виявлення +неправильних конфігурацій вузлів. + +## Пропущений слот (skipped slot) + +Минулий [слот](#slot), у якому не було створено [блоку](#block), тому що лідер +був офлайн або [форк](#fork), що містить цей слот, був залишений на користь +кращого варіанту за консенсусом кластера. Пропущений слот не з’явиться як предок +для блоків у наступних слотах, не збільшить [висоту блоку](#block-height) і не +призведе до прострочення найстарішого `recent_blockhash`. + +Чи було пропущено слот, можна визначити лише тоді, коли він стає старішим за +останній [корінний](#root) (а отже, не пропущений) слот. + +## Слот (slot) + +Проміжок часу, протягом якого кожен [лідер](#leader) приймає транзакції та +створює [блок](#block). + +Колективно слоти створюють логічний годинник. Слоти упорядковані послідовно та +не перекриваються, охоплюючи приблизно однакові інтервали реального часу +відповідно до [PoH](#proof-of-history-poh). + +## Розумний контракт (smart contract) + +Див. [Програма на блокчейні](#onchain-program). + +## SOL + +[Нативний токен](#native-token) [кластеру](#cluster) Solana. + +## Бібліотека програм Solana (SPL) + +[Бібліотека програм](https://spl.solana.com/) на Solana, таких як spl-token, що +сприяють виконанню завдань, як-от створення та використання токенів. + +## Ставка (stake) + +Токени, які можуть бути конфісковані [кластером](#cluster), якщо буде доведено +зловмисну поведінку [валідатора](#validator). + +## Якість обслуговування з урахуванням ставки (stake-weighted quality of service, SWQoS) + +SWQoS дозволяє +[надавати перевагу транзакціям, які надходять від валідаторів із поставленими токенами](https://solana.com/developers/guides/advanced/stake-weighted-qos). + +## Супербільшість (supermajority) + +2/3 [кластеру](#cluster). + +## Системна змінна (sysvar) + +Системний [обліковий запис](#account). +[Системні змінні (Sysvars)](https://docs.anza.xyz/runtime/sysvars) надають +інформацію про стан кластера, наприклад поточну висоту тіку, значення винагород +[очок](#point) тощо. Програми можуть отримати доступ до системних змінних через +обліковий запис Sysvar (публічний ключ) або запитати через системний виклик. + +## Тонкий клієнт (thin client) + +Тип [клієнта](#client), який довіряє, що він підключений до дійсного +[кластеру](#cluster). + +## Тік (tick) + +[Запис](#entry) у реєстрі, який оцінює тривалість реального часу. + +## Висота тіку (tick height) + +N-тий [тік](#tick) у [реєстрі](#ledger). + +## Токен (token) + +Цифровий актив, що підлягає передачі. + +## Програма розширення токенів (Token Extensions Program) + +[Програма розширення токенів](https://spl.solana.com/token-2022) має +ідентифікатор `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb` і включає всі ті +самі функції, що й [Програма токенів](#token-program), але додає розширення, +як-от конфіденційні перекази, кастомна логіка переказу, розширені метадані тощо. + +## Карбування токенів (token mint) + +Обліковий запис, який може створювати токени. Різні токени відрізняються за +унікальними адресами карбування токенів. + +## Програма токенів (Token Program) + +[Програма токенів](https://spl.solana.com/token) має ідентифікатор +`TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA` і надає базові можливості +передачі, заморожування та карбування токенів. + +## TPS + +[Транзакції](#transaction) за секунду. + +## TPU + +[Підрозділ обробки транзакцій](https://docs.anza.xyz/validator/tpu). + +## Транзакція (transaction) + +Одна або кілька [інструкцій](#instruction), підписаних [клієнтом](#client) за +допомогою однієї або кількох [пар ключів](#keypair), виконуються атомарно з +двома можливими результатами: успіх або невдача. + +## Ідентифікатор транзакції (transaction id) + +Перший [підпис](#signature) у [транзакції](#transaction), який можна +використовувати для унікальної ідентифікації транзакції у повному +[реєстрі](#ledger). + +## Підтвердження транзакції (transaction confirmations) + +Кількість [підтверджених блоків](#confirmed-block) з моменту прийняття +транзакції до [реєстру](#ledger). Транзакція завершується, коли її блок стає +[коренем](#root). + +## Запис транзакцій (transactions entry) + +Набір [транзакцій](#transaction), які можна виконувати паралельно. + +## TVU + +[Підрозділ перевірки транзакцій](https://docs.anza.xyz/validator/tvu). + +## Валідатор (validator) + +Повноцінний учасник мережі Solana, який створює нові [блоки](#block). Валідатор +перевіряє транзакції, додані до [реєстру](#ledger). + +## VDF + +Див. [Перевірювана функція затримки](#verifiable-delay-function-vdf). + +## Перевірювана функція затримки (VDF) + +Функція, яка займає фіксований проміжок часу для виконання та генерує доказ, що +вона виконалася. Цей доказ можна перевірити швидше, ніж час, необхідний для його +створення. + +## Голос (vote) + +Див. [Голос у реєстрі](#ledger-vote). + +## Кредит голосування (vote credit) + +Нарахування винагороди для [валідаторів](#validator). Кредит голосування +присуджується валідатору на його рахунок голосування, коли він досягає +[кореня](#root). + +## Гаманець (wallet) + +Набір [пар ключів](#keypair), який дозволяє користувачам керувати своїми +коштами. + +## Період прогріву (warmup period) + +Декілька [епох](#epoch) після делегування [ставки](#stake), протягом яких вона +поступово стає активною. Під час цього періоду ставка вважається "активованою". +Докладніше: +[періоди прогріву та охолодження](https://docs.anza.xyz/consensus/stake-delegation-and-rewards#stake-warmup-cooldown-withdrawal).