Краткое резюме
Итоговая комиссия = базовая комиссия (5 000 lamport/подпись, 50% сжигается) + комиссия за приоритизацию (CU_price * CU_limit / 1M lamport, 100% validator'у). Взимается независимо от того, выполнена транзакция успешно или нет.
Алгоритм расчёта комиссии
Итоговая комиссия за транзакцию вычисляется функцией
calculate_fee_details:
total_fee = base_fee + prioritization_fee
На входе — сообщение транзакции, текущее значение lamports_per_signature
(в настоящее время 5 000) и комиссия за приоритизацию, полученная из инструкций вычислительного бюджета. Итоговая комиссия списывается с плательщика комиссии до начала выполнения.
Если транзакция завершается с ошибкой, комиссия всё равно взимается.
Базовая комиссия
Базовая комиссия покрывает стоимость верификации подписей Ed25519, а также верификации подписей прекомпилированными программами. С каждой подписи в транзакции взимается комиссия, включая подписи, верифицированные прекомпилированными программами Ed25519, Secp256k1 и Secp256r1.
Функция
calculate_signature_fee
вычисляет:
signature_count = num_transaction_signatures+ num_ed25519_signatures+ num_secp256k1_signatures+ num_secp256r1_signatures (if feature enabled)base_fee = signature_count * lamports_per_signature
num_transaction_signatures: количество подписей Ed25519 в транзакции (как правило, по одной на каждого подписанта).num_ed25519_signatures,num_secp256k1_signatures,num_secp256r1_signatures: подписи, верифицированные соответствующими прекомпилированными программами.lamports_per_signature: в настоящее время 5 000 lamport.
Распределение комиссий
Базовая комиссия и комиссия за приоритизацию распределяются по-разному. Функция
calculate_reward_and_burn_fee_details
в среде выполнения вычисляет:
burn_amount = transaction_fee * 50 / 100validator_share = (transaction_fee - burn_amount) + priority_fee
- Базовая комиссия (transaction_fee): 50%
сжигается
(изымается из обращения), а 50% направляется validator'у, создающему блок. Процент сжигания задаётся константой
DEFAULT_BURN_PERCENT = 50. - Комиссия за приоритизацию: 100% направляется validator'у (ничего не сжигается), согласно SIMD-0096.
Итоговое вознаграждение validator'а за транзакцию составляет:
validator_reward = (base_fee / 2) + prioritization_fee
Комиссия за приоритизацию
Комиссия за приоритизацию — это необязательная комиссия, повышающая приоритет планирования транзакции. Вычислительная единица (CU) — это единица измерения вычислений, которую среда выполнения отслеживает в ходе выполнения транзакции. Каждая операция (арифметическая, обращение к памяти, системный вызов) стоит фиксированное количество CU. Задать комиссию за приоритизацию можно, включив инструкции вычислительного бюджета в свою транзакцию. (Подробнее см. руководство «Как использовать комиссии за приоритет».)
Формула комиссии за приоритизацию
Функция
get_prioritization_fee
вычисляет:
micro_lamport_fee = compute_unit_price * compute_unit_limitprioritization_fee = ceil(micro_lamport_fee / 1,000,000)
| Переменная | Описание | По умолчанию |
|---|---|---|
compute_unit_price | Микро-lamport за CU, задаётся через SetComputeUnitPrice | 0 микро-lamport |
compute_unit_limit | Максимальное количество CU, которое может использовать транзакция; задаётся через SetComputeUnitLimit | Сумма значений по умолчанию для каждой инструкции |
1 000 000 | Коэффициент пересчёта микро-lamport в lamport (MICRO_LAMPORTS_PER_LAMPORT) | -- |
Транзакции v1 задают комиссию напрямую
Формула цена × лимит применяется к устаревшим транзакциям и транзакциям v0. В формате v1 комиссия за приоритизацию задаётся как абсолютная итоговая сумма в lamport непосредственно в конфигурации сообщения — без цены за CU, без умножения и без округления.
Лимит вычислительных единиц
Лимит вычислительных единиц — это максимальное количество CU, которое может использовать транзакция.
Если инструкция
SetComputeUnitLimit
не включена, значение по умолчанию рассчитывается исходя из количества и типа инструкций (200 000 CU для каждой встроенной инструкции, 3 000 — для каждой нативной). Подробнее о расчёте по умолчанию см. в разделе
«Вычислительный бюджет».
Комиссия за приоритизацию рассчитывается на основе запрошенного лимита CU, а не фактически использованного. Установка лимита выше необходимого означает оплату неиспользованных вычислительных единиц.
Цена вычислительной единицы
Цена вычислительной единицы — это необязательная сумма в микро-lamport, уплачиваемая за каждую запрошенную CU. Цена CU напрямую определяет комиссию за приоритизацию. Чтобы задать цену CU, включите инструкцию
SetComputeUnitPrice
в свою транзакцию.
Цена CU по умолчанию равна 0, поэтому комиссия за приоритизацию по умолчанию также равна 0.
Актуальные оценки цены CU в реальном времени предоставляют указанные ниже провайдеры API комиссий за приоритет.
| Провайдер | API комиссий за приоритет |
|---|---|
| Helius | Документация |
| QuickNode | Документация |
| Triton | Документация |
Приоритет планирования транзакций
Планировщик ранжирует транзакции с помощью функции
calculate_priority_and_cost:
Priority = reward * 1,000,000 / (cost + 1)
- reward — доход validator'а от комиссий = комиссия за приоритизацию + не сожжённая
часть базовой комиссии. Вычисляется функцией
calculate_reward_for_transaction. - cost — расчётная стоимость CU по оценке планировщика (estimated CU cost): стоимость подписей + стоимость блокировок на запись + стоимость instruction data + стоимость выполнения программы + стоимость загрузки данных аккаунтов. Подробнее см. в разделе «Вычислительный бюджет».
- 1 000 000 — множитель для сохранения точности, поскольку стоимость нередко превышает вознаграждение в абсолютных значениях lamport.
- +1 — защита от деления на ноль.
Приоритет определяет порядок, в котором транзакции извлекаются из буфера планировщика для выполнения.
Пример: установка лимита CU и цены CU
В приведённых ниже примерах показано, как задать лимит CU и цену CU для транзакции с помощью SDK Solana.
| SDK | Ссылка на исходный код |
|---|---|
@solana/web3.js (Typescript) | ComputeBudgetProgram |
solana-sdk (Rust) | ComputeBudgetInstruction |
const limitInstruction = ComputeBudgetProgram.setComputeUnitLimit({units: 300_000});const priceInstruction = ComputeBudgetProgram.setComputeUnitPrice({microLamports: 1});
import {LAMPORTS_PER_SOL,SystemProgram,Transaction,Keypair,Connection,ComputeBudgetProgram,sendAndConfirmTransaction} from "@solana/web3.js";const connection = new Connection("http://localhost:8899", "confirmed");const sender = Keypair.generate();const recipient = new Keypair();const airdropSignature = await connection.requestAirdrop(sender.publicKey,LAMPORTS_PER_SOL);await connection.confirmTransaction(airdropSignature, "confirmed");// Create compute budget instructionsconst limitInstruction = ComputeBudgetProgram.setComputeUnitLimit({units: 300_000});const priceInstruction = ComputeBudgetProgram.setComputeUnitPrice({microLamports: 1});const transferInstruction = SystemProgram.transfer({fromPubkey: sender.publicKey,toPubkey: recipient.publicKey,lamports: 0.01 * LAMPORTS_PER_SOL});// Add the compute budget and transfer instructions to a new transactionconst transaction = new Transaction().add(limitInstruction).add(priceInstruction).add(transferInstruction);const signature = await sendAndConfirmTransaction(connection, transaction, [sender]);console.log("Transaction Signature:", signature);
Is this page helpful?