Підсумок
Перевірки середовища виконання після кожної інструкції: лише власник може списувати lamports або змінювати дані, дані можуть зростати максимум на 10 КіБ за інструкцію, зміна власника вимагає нульових даних, а прапорець executable є незворотним.
Середовище виконання Solana застосовує ці правила після виконання кожної
інструкції через методи
BorrowedInstructionAccount.
Кожне правило перевіряється в момент модифікації, і транзакція відкочується,
якщо будь-яка перевірка не вдається.
Правила lamports
| Правило | Застосування | Помилка |
|---|---|---|
| Лише власник може списувати lamports | set_lamports(): перевіряє is_owned_by_current_program(), коли lamports < current | ExternalAccountLamportSpend |
| Облікові записи лише для читання не можуть мати змінені lamports | set_lamports(): перевіряє is_writable() | ReadonlyLamportChange |
| Будь-яка програма може зараховувати lamports на обліковий запис для запису | set_lamports(): перевірка власності застосовується лише коли новий баланс менший за поточний; перевірка можливості запису все одно застосовується | ReadonlyLamportChange |
| Lamports мають балансуватися в межах інструкції | TransactionContext::pop(): перевіряє get_lamports_delta() == 0 | UnbalancedInstruction |
Правила даних
| Правило | Застосування | Помилка |
|---|---|---|
| Лише власник може змінювати дані | can_data_be_changed(): перевіряє is_owned_by_current_program() | ExternalAccountDataModified |
| Облікові записи лише для читання не можуть мати змінені дані | can_data_be_changed(): перевіряє is_writable() | ReadonlyDataModified |
| Лише власник може змінювати розмір даних | can_data_be_resized(): перевіряє is_owned_by_current_program(), коли new_len != old_len | AccountDataSizeChanged |
| Максимальний розмір даних: 10 МіБ | TransactionAccounts::can_data_be_resized(): перевіряє new_len <= MAX_ACCOUNT_DATA_LEN | InvalidRealloc |
| Максимальне зростання за інструкцію: 10 КіБ | Десеріалізація в deserialize_parameters_aligned(): перевіряє post_len - pre_len <= MAX_PERMITTED_DATA_INCREASE | InvalidRealloc |
| Максимальне зростання за транзакцію: 20 МіБ | TransactionAccounts::can_data_be_resized(): перевіряє кумулятивне resize_delta <= MAX_ACCOUNT_DATA_GROWTH_PER_TRANSACTION | MaxAccountsDataAllocationsExceeded |
Правила власника
| Правило | Застосування | Помилка |
|---|---|---|
| Лише поточний власник може переназначити власника | set_owner(): перевіряє is_owned_by_current_program() | ModifiedProgramId |
| Акаунт має бути доступним для запису | set_owner(): перевіряє is_writable() | ModifiedProgramId |
| Дані мають бути ініціалізовані нулями | set_owner(): перевіряє is_zeroed(data) | ModifiedProgramId |
Правила прапорця виконуваності
| Правило | Застосування | Помилка |
|---|---|---|
| Акаунт має бути звільнений від rent | set_executable(): перевіряє rent.is_exempt(lamports, data_len) | ExecutableAccountNotRentExempt |
| Лише власник може встановити прапорець | set_executable(): перевіряє is_owned_by_current_program() | ExecutableModified |
| Акаунт має бути доступним для запису | set_executable(): перевіряє is_writable() | ExecutableModified |
Переходи стану rent
Акаунти існують в одному з трьох
RentState
значень: Uninitialized (0 lamports), RentPaying (вище 0, але нижче
мінімуму для звільнення від rent), та RentExempt (на рівні або вище
мінімуму). Заборонені переходи призводять до
TransactionError::InsufficientFundsForRent.
Середовище виконання застосовує ці правила через
transition_allowed():
- Будь-який акаунт може перейти до
Uninitialized(закрити) абоRentExempt. - Жоден акаунт не може перейти до
RentPayingзUninitializedабоRentExempt. Усі нові акаунти мають бути звільнені від rent.
Правила запозичення акаунтів
Під час виконання інструкції середовище виконання застосовує семантику одного
записувача для запозичення акаунтів. Програма може отримати або одне змінне
посилання, або кілька незмінних посилань на акаунт, але не обидва одночасно.
Якщо програма намагається запозичити акаунт, який уже запозичено зі зміною (або
запозичити зі зміною акаунт, який уже запозичено без зміни), інструкція
завершується помилкою AccountBorrowFailed через
try_borrow()
та
try_borrow_mut().
Якщо інструкція завершується, поки запозичення все ще активне, середовище
виконання повертає AccountBorrowOutstanding у
TransactionContext::pop().
Is this page helpful?