Кратко
Общая комиссия = базовая комиссия (5 000 лампортов/подпись, 50% сжигается) + приоритетная комиссия (CU_price * CU_limit / 1M лампортов, 100% — валидатору). Взимается независимо от того, прошла ли транзакция успешно или нет.
Алгоритм расчёта комиссии
Общая комиссия за транзакцию вычисляется по
calculate_fee_details:
total_fee = base_fee + prioritization_fee
Входными данными являются сообщение транзакции, текущее значение
lamports_per_signature (в настоящее время 5 000) и приоритетная комиссия,
определяемая инструкциями compute budget. Общая комиссия списывается с
плательщика комиссии до начала выполнения. Если транзакция не проходит, комиссия
всё равно взимается.
Базовая комиссия
Базовая комиссия покрывает стоимость проверки подписи Ed25519, а также любых проверок подписей через precompile-программы. За каждую подпись в транзакции взимается комиссия, включая подписи, проверяемые программами 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: подписи, проверяемые соответствующими precompile-программами.lamports_per_signature: в настоящее время 5 000 лампортов.
Распределение комиссии
Базовая комиссия и приоритетная комиссия распределяются по-разному. Функция
calculate_reward_and_burn_fee_details
в рантайме вычисляет:
burn_amount = transaction_fee * 50 / 100validator_share = (transaction_fee - burn_amount) + priority_fee
- Базовая комиссия (transaction_fee): 50%
сжигается
(удаляется из обращения), а 50% получает валидатор, создавший блок. Процент
сжигания —
DEFAULT_BURN_PERCENT = 50. - Приоритетная комиссия: 100% получает валидатор (ничего не сжигается), согласно SIMD-0096.
Общая награда validator за транзакцию:
validator_reward = (base_fee / 2) + prioritization_fee
Приоритетная комиссия
Приоритетная комиссия — это необязательная плата, которая увеличивает приоритет выполнения транзакции. Compute unit (CU, вычислительная единица) — это единица вычислений, которую runtime учитывает при выполнении транзакции. Каждая операция (арифметика, доступ к памяти, системный вызов) стоит определённое количество CU. Вы можете установить приоритетную комиссию, добавив инструкции compute budget в вашу транзакцию. (Подробнее см. в руководстве по использованию приоритетных комиссий.)
Формула приоритетной комиссии
Функция
get_prioritization_fee
вычисляет:
micro_lamport_fee = compute_unit_price * compute_unit_limitprioritization_fee = ceil(micro_lamport_fee / 1,000,000)
| Переменная | Описание | Значение по умолчанию |
|---|---|---|
compute_unit_price | Микролампортов за CU, устанавливается через SetComputeUnitPrice | 0 микролампортов |
compute_unit_limit | Максимальное количество CU, которое может использовать транзакция, устанавливается через SetComputeUnitLimit | Сумма значений по умолчанию для каждой инструкции |
1,000,000 | Коэффициент преобразования микролампортов в лампорты (MICRO_LAMPORTS_PER_LAMPORT) | -- |
Лимит вычислительных единиц
Лимит вычислительных единиц — это максимальное количество CU, которое может
использовать транзакция. Если инструкция
SetComputeUnitLimit
не включена, значение по умолчанию рассчитывается исходя из количества и типа
инструкций (200 000 CU на каждую не встроенную инструкцию, 3 000 — на
встроенную). Подробнее о расчёте по умолчанию см. в разделе
Compute Budget.
Приоритетная комиссия рассчитывается на основе запрошенного лимита CU, а не фактического использования CU. Если установить лимит выше необходимого, придётся платить за неиспользованные вычислительные единицы.
Цена вычислительной единицы
Цена вычислительной единицы — это необязательная сумма в микролампортах, которую
платят за каждую запрошенную 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: доход валидатора от комиссии = комиссия за приоритет + не
сожжённая часть базовой комиссии. Рассчитывается с помощью
calculate_reward_for_transaction. - cost: оценочная стоимость CU для планировщика (стоимость подписи + стоимость write lock + стоимость instruction data + стоимость выполнения программы + стоимость загруженных аккаунтов по размеру данных). Подробнее см. в разделе Compute Budget.
- 1 000 000: множитель для сохранения точности, так как стоимость часто превышает доход в необработанных лампортах.
- +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?