docs: prioritization fees (#30138)

* docs: updated prioritization fees docs

* fix: updated wording and removed outdated info

* docs: updated prioritization fees docs

* fix: merge fix

---------

Co-authored-by: nickfrosty <nick.frostbutter@solana.org>
This commit is contained in:
Nick Frostbutter 2023-03-14 14:31:41 -04:00 committed by GitHub
parent b389d509a8
commit f528335ac0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 192 additions and 84 deletions

View File

@ -39,7 +39,7 @@ An array of `RpcPrioritizationFee<object>` with the following fields:
- `slot: <u64>` - slot in which the fee was observed
- `prioritizationFee: <u64>` - the per-compute-unit fee paid by at least
one successfully landed transaction, specified in increments of 0.000001 lamports
one successfully landed transaction, specified in increments of micro-lamports (0.000001 lamports)
</CodeParams>

View File

@ -70,26 +70,3 @@ Before any transaction instructions are processed, the fee payer account balance
### Fee Distribution
Transaction fees are partially burned and the remaining fees are collected by the validator that produced the block that the corresponding transactions were included in. The transaction fee burn rate was initialized as 50% when inflation rewards were enabled at the beginning of 2021 and has not changed so far. These fees incentivize a validator to process as many transactions as possible during its slots in the leader schedule. Collected fees are deposited in the validator's account (listed in the leader schedule for the current slot) after processing all of the transactions included in a block.
## Upcoming Changes
### Transaction wide compute budget
As of version 1.8 of the Solana protocol, the maximum compute budget for transactions is assessed on a per instruction basis. This has allowed for flexibility in protocol design to squeeze out more compute by splitting up operations across multiple instructions but this workaround has skewed the distribution of compute consumption across different transactions. To keep transaction fees properly priced, the maximum compute budget will instead be assessed over the entire transaction. This change is likely to be released in version 1.9 of the Solana protocol and is gated on the following feature switch:
```bash
$ ~/Workspace/solana (master branch) > cargo run --bin solana -- feature status 5ekBxc8itEnPv4NzGJtr8BVVQLNMQuLMNQQj7pHoLNZ9 --url mainnet-beta
5ekBxc8itEnPv4NzGJtr8BVVQLNMQuLMNQQj7pHoLNZ9 | inactive | transaction wide compute cap
```
This adjustment could negatively impact the usability of some protocols which have relied on the compute budget being reset for each instruction in a transaction. For this reason, this compute budget change will not be enabled until a new mechanism for increasing total transaction compute budget is added. This mechanism is described below...
### Request increased compute budget
As protocols have gotten more complex, the [default compute budget of 200,000 compute units](https://github.com/solana-labs/solana/blob/647aa926673e3df4443d8b3d9e3f759e8ca2c44b/sdk/src/compute_budget.rs#L105) has become a common pain-point for developers. Developers have gotten creative in working around this limitation by breaking up operations across multiple instructions and/or transactions. But in order to properly address this issue, a new program instruction will be added to request additional compute units from the runtime (up to a max of 1 million compute units). To request more compute, [create a `RequestUnits` instruction which invokes the new `Compute Budget` program](https://github.com/solana-labs/solana/blob/647aa926673e3df4443d8b3d9e3f759e8ca2c44b/sdk/src/compute_budget.rs#L44) and insert it at the beginning of a transaction. This new program will be released along with the transaction-wide compute budget change described above and is gated on the same feature switch. There are currently no increased transaction fees for using this feature, however that is likely to change.
Note that adding a `RequestUnits` compute budget instruction will take up 39 extra bytes in a serialized transaction. That breaks down into 32 bytes for the compute budget program id, 1 byte for program id index, 1 byte for empty ix account vec len, 1 byte for data vec len, and 4 bytes for the requested compute.
### Calculate transaction fees with RPC API
In order to simplify fee calculation for developers, a new [`getFeeForMessage`](/api/http#getfeeformessage) RPC API is planned to be released in v1.9 of the Solana protocol. This new method accepts a blockhash along with an encoded transaction message and will return the amount of fees that would be deducted if the transaction message is signed, sent, and processed by the cluster.

View File

@ -116,40 +116,19 @@ for more information.
### Prioritization fees
A transaction may set the maximum number of compute units it is allowed to
consume and the compute unit price by including a `SetComputeUnitLimit` and a
`SetComputeUnitPrice`
[Compute budget instructions](https://github.com/solana-labs/solana/blob/db32549c00a1b5370fcaf128981ad3323bbd9570/sdk/src/compute_budget.rs#L22)
respectively.
As part of the Compute Budget, the runtime supports transactions including an
**optional** fee to prioritize itself against others known as a
[prioritization fee](./../../transaction_fees.md#prioritization-fee).
If no `SetComputeUnitLimit` is provided the limit will be calculated as the
product of the number of instructions in the transaction (excluding the [Compute
budget instructions](https://github.com/solana-labs/solana/blob/db32549c00a1b5370fcaf128981ad3323bbd9570/sdk/src/compute_budget.rs#L22)) and the default per-instruction units, which is currently 200k.
This _prioritization fee_ is calculated by multiplying the number
of _compute units_ by the _compute unit price_ (measured in micro-lamports).
These values may be set via the Compute Budget instructions `SetComputeUnitLimit`
and `SetComputeUnitPrice` once per transaction.
> **NOTE:** A transaction's [prioritization fee](./../../terminology.md#prioritization-fee) is calculated by multiplying the
> number of _compute units_ by the _compute unit price_ (measured in micro-lamports)
> set by the transaction via compute budget instructions.
Transactions should request the minimum amount of compute units required for execution to minimize
fees. Also note that fees are not adjusted when the number of requested compute
units exceeds the number of compute units actually consumed by an executed
transaction.
Compute Budget instructions don't require any accounts and don't consume any
compute units to process. Transactions can only contain one of each type of
compute budget instruction, duplicate types will result in an error.
The `ComputeBudgetInstruction::set_compute_unit_limit` and
`ComputeBudgetInstruction::set_compute_unit_price` functions can be used to
create these instructions:
```rust
let instruction = ComputeBudgetInstruction::set_compute_unit_limit(300_000);
```
```rust
let instruction = ComputeBudgetInstruction::set_compute_unit_price(1);
```
:::info
You can learn more of the specifics of _how_ and _when_ to set a prioritization fee
on the [transaction fees](./../../transaction_fees.md#prioritization-fee) page.
:::
### Accounts data size limit

View File

@ -169,6 +169,10 @@ A [public key](#public-key-pubkey) and corresponding [private key](#private-key)
A fractional [native token](#native-token) with the value of 0.000000001 [sol](#sol).
:::info
Within the compute budget, a quantity of _[micro-lamports](https://github.com/solana-labs/solana/blob/ced8f6a512c61e0dd5308095ae8457add4a39e94/program-runtime/src/prioritization_fee.rs#L1-L2)_ is used in the calculation of [prioritization fees](#prioritization-fee).
:::
## leader
The role of a [validator](#validator) when it is appending [entries](#entry) to the [ledger](#ledger).

View File

@ -1,6 +1,9 @@
---
title: Transaction Fees
description: "Transaction fees are the small fees paid to process instructions on the network. These fees are based on computation and an optional prioritization fee."
description:
"Transaction fees are the small fees paid to process instructions on the
network. These fees are based on computation and an optional prioritization
fee."
keywords:
- instruction fee
- processing fee
@ -12,46 +15,73 @@ keywords:
- affordable blockchain
---
The small fees paid to process [instructions](./terminology.md#instruction) on the Solana blockchain are known as "_transaction fees_".
The small fees paid to process [instructions](./terminology.md#instruction) on
the Solana blockchain are known as "_transaction fees_".
As each transaction (which contains one or more instructions) is sent through the network, it gets processed by the current leader validation-client. Once confirmed as a global state transaction, this _transaction fee_ is paid to the network to help support the [economic design](#economic-design) of the Solana blockchain.
As each transaction (which contains one or more instructions) is sent through
the network, it gets processed by the current leader validation-client. Once
confirmed as a global state transaction, this _transaction fee_ is paid to the
network to help support the [economic design](#economic-design) of the Solana
blockchain.
> **NOTE:** Transaction fees are different from [account rent](./terminology.md#rent)!
> While transaction fees are paid to process instructions on the Solana network, rent is paid to store data on the blockchain.
> **NOTE:** Transaction fees are different from
> [account rent](./terminology.md#rent)! While transaction fees are paid to
> process instructions on the Solana network, rent is paid to store data on the
> blockchain.
> You can learn more about rent here: [What is rent?](./developing/intro/rent.md)
> You can learn more about rent here:
> [What is rent?](./developing/intro/rent.md)
## Why pay transaction fees?
Transaction fees offer many benefits in the Solana [economic design](#basic-economic-design) described below. Mainly:
Transaction fees offer many benefits in the Solana
[economic design](#basic-economic-design) described below. Mainly:
- they provide compensation to the validator network for the CPU/GPU resources necessary to process transactions,
- they provide compensation to the validator network for the CPU/GPU resources
necessary to process transactions,
- reduce network spam by introducing real cost to transactions,
- and provide long-term economic stability to the network through a protocol-captured minimum fee amount per transaction
- and provide long-term economic stability to the network through a
protocol-captured minimum fee amount per transaction
> **NOTE:** Network consensus votes are sent as normal system transfers, which means that validators pay transaction fees to participate in consensus.
> **NOTE:** Network consensus votes are sent as normal system transfers, which
> means that validators pay transaction fees to participate in consensus.
## Basic economic design
Many blockchain networks \(e.g. Bitcoin and Ethereum\), rely on inflationary _protocol-based rewards_ to secure the network in the short-term. Over the long-term, these networks will increasingly rely on _transaction fees_ to sustain security.
Many blockchain networks \(e.g. Bitcoin and Ethereum\), rely on inflationary
_protocol-based rewards_ to secure the network in the short-term. Over the
long-term, these networks will increasingly rely on _transaction fees_ to
sustain security.
The same is true on Solana. Specifically:
- A fixed proportion (initially 50%) of each transaction fee is _burned_ (destroyed), with the remaining going to the current [leader](./terminology.md#leader) processing the transaction.
- A scheduled global inflation rate provides a source for [rewards](./implemented-proposals/staking-rewards.md) distributed to [Solana Validators](../src/running-validator.md).
- A fixed proportion (initially 50%) of each transaction fee is _burned_
(destroyed), with the remaining going to the current
[leader](./terminology.md#leader) processing the transaction.
- A scheduled global inflation rate provides a source for
[rewards](./implemented-proposals/staking-rewards.md) distributed to
[Solana Validators](../src/running-validator.md).
### Why burn some fees?
As mentioned above, a fixed proportion of each transaction fee is _burned_ (destroyed). This is intended to cement the economic value of SOL and thus sustain the network's security. Unlike a scheme where transactions fees are completely burned, leaders are still incentivized to include as many transactions as possible in their slots.
As mentioned above, a fixed proportion of each transaction fee is _burned_
(destroyed). This is intended to cement the economic value of SOL and thus
sustain the network's security. Unlike a scheme where transactions fees are
completely burned, leaders are still incentivized to include as many
transactions as possible in their slots.
Burnt fees can also help prevent malicious validators from censoring transactions by being considered in [fork](./terminology.md#fork) selection.
Burnt fees can also help prevent malicious validators from censoring
transactions by being considered in [fork](./terminology.md#fork) selection.
#### Example of an attack:
In the case of a [Proof of History (PoH)](./terminology.md#proof-of-history-poh) fork with a malicious, censoring leader:
In the case of a [Proof of History (PoH)](./terminology.md#proof-of-history-poh)
fork with a malicious, censoring leader:
- due to the fees lost from censoring, we would expect the total fees burned to be **_less than_** a comparable honest fork
- if the censoring leader is to compensate for these lost protocol fees, they would have to replace the burnt fees on their fork themselves
- due to the fees lost from censoring, we would expect the total fees burned to
be **_less than_** a comparable honest fork
- if the censoring leader is to compensate for these lost protocol fees, they
would have to replace the burnt fees on their fork themselves
- thus potentially reducing the incentive to censor in the first place
## Calculating transaction fees
@ -59,28 +89,146 @@ In the case of a [Proof of History (PoH)](./terminology.md#proof-of-history-poh)
Transactions fees are calculated based on two main parts:
- a statically set base fee per signature, and
- the computational resources used during the transaction, measured in "[_compute units_](./terminology.md#compute-units)"
- the computational resources used during the transaction, measured in
"[_compute units_](./terminology.md#compute-units)"
Since each transaction may require a different amount of computational resources, they are alloted a maximum number of _compute units_ per transaction known as the "[_compute budget_](./terminology.md#compute-budget)".
Since each transaction may require a different amount of computational
resources, they are alloted a maximum number of _compute units_ per transaction
known as the "[_compute budget_](./terminology.md#compute-budget)".
The execution of each instruction within a transaction consumes a different number of _compute units_. After the maximum number of _compute units_ has been consumed (aka compute budget exhaustion), the runtime will halt the transaction and return an error. This results in a failed transaction.
The execution of each instruction within a transaction consumes a different
number of _compute units_. After the maximum number of _compute units_ has been
consumed (aka compute budget exhaustion), the runtime will halt the transaction
and return an error. This results in a failed transaction.
> **Learn more:** compute units and the [Compute Budget](./developing/programming-model/runtime#compute-budget) in the Runtime and [requesting a fee estimate](../api/http#getfeeformessage) from the RPC.
> **Learn more:** compute units and the
> [Compute Budget](./developing/programming-model/runtime#compute-budget) in the
> Runtime and [requesting a fee estimate](../api/http#getfeeformessage) from the
> RPC.
## Prioritization fee
Recently, Solana has introduced an optional fee called the "_[prioritization fee](./terminology.md#prioritization-fee)_". This additional fee can be paid to help boost how a transaction is prioritized against others, resulting in faster transaction execution times.
A Solana transaction can include an **optional** fee to prioritize itself
against others known as a
"_[prioritization fee](./terminology.md#prioritization-fee)_". Paying this
additional fee helps boost how a transaction is prioritized against others,
resulting in faster execution times.
The prioritization fee is calculated by multiplying the requested maximum _compute units_ by the compute-unit price (specified in increments of 0.000001 lamports per compute unit) rounded up to the nearest lamport.
### How the prioritization fee is calculated
You can read more about the [compute budget instruction](./developing/programming-model/runtime.md#compute-budget) here.
A transaction's [prioritization fee](./terminology.md#prioritization-fee) is
calculated by multiplying the maximum number of **_compute units_** by the
**_compute unit price_** (measured in _micro-lamports_).
Each transaction can set the maximum number of compute units it is allowed to
consume and the compute unit price by including a `SetComputeUnitLimit` and
`SetComputeUnitPrice` compute budget instruction respectively.
:::info
[Compute Budget instructions](https://github.com/solana-labs/solana/blob/master/sdk/src/compute_budget.rs)
do **not** require any accounts. :::
If no `SetComputeUnitLimit` instruction is provided, the limit will be
calculated as the product of the number of instructions in the transaction and
the default per-instruction units, which is currently
[200k](https://github.com/solana-labs/solana/blob/4293f11cf13fc1e83f1baa2ca3bb2f8ea8f9a000/program-runtime/src/compute_budget.rs#L13).
If no `SetComputeUnitPrice` instruction is provided, the transaction will
default to no additional elevated fee and the lowest priority.
### How to set the prioritization fee
A transaction's prioritization fee is set by including a `SetComputeUnitPrice`
instruction, and optionally a `SetComputeUnitLimit` instruction. The runtime
will use these values to calculate the prioritization fee, which will be used to
prioritize the given transaction within the block.
You can craft each of these instructions via their `rust` or `@solana/web3.js`
functions. Each of these instructions can then be included in the transaction
and sent to the cluster like normal. See also the
[best practices](#prioritization-fee-best-practices) below.
:::caution Transactions can only contain **one of each type** of compute budget
instruction. Duplicate types will result in an
[`TransactionError::DuplicateInstruction`](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction/error.rs#L144-145)
error, and ultimately transaction failure. :::
#### Rust
The rust `solana-sdk` crate includes functions within
[`ComputeBudgetInstruction`](https://docs.rs/solana-sdk/latest/solana_sdk/compute_budget/enum.ComputeBudgetInstruction.html)
to craft instructions for setting the _compute unit limit_ and _compute unit
price_:
```rust
let instruction = ComputeBudgetInstruction::set_compute_unit_limit(300_000);
```
```rust
let instruction = ComputeBudgetInstruction::set_compute_unit_price(1);
```
#### Javascript
The `@solana/web3.js` library includes functions within the
[`ComputeBudgetProgram`](https://solana-labs.github.io/solana-web3.js/classes/ComputeBudgetProgram.html)
class to craft instructions for setting the _compute unit limit_ and _compute
unit price_:
```js
const instruction = ComputeBudgetProgram.setComputeUnitLimit({
units: 300_000,
});
```
```js
const instruction = ComputeBudgetProgram.setComputeUnitPrice({
microLamports: 1,
});
```
### Prioritization fee best practices
#### Request the minimum compute units
Transactions should request the minimum amount of compute units required for
execution to minimize fees. Also note that fees are not adjusted when the number
of requested compute units exceeds the number of compute units actually consumed
by an executed transaction.
#### Get recent prioritization fees
Prior to sending a transaction to the cluster, you can use the
[`getRecentPrioritizationFees`](/api/http#getrecentprioritizationfees) RPC
method to get a list of the recent paid prioritization fees within the recent
blocks processed by the node.
You could then use this data to estimate an appropriate prioritization fee for
your transaction to both (a) better ensure it gets processed by the cluster and
(b) minimize the fees paid.
## Fee Collection
Transactions are required to have at least one account which has signed the transaction and is writable. Writable signer accounts are serialized first in the list of transaction accounts and the first of these accounts is always used as the "fee payer".
Transactions are required to have at least one account which has signed the
transaction and is writable. Writable signer accounts are serialized first in
the list of transaction accounts and the first of these accounts is always used
as the "fee payer".
Before any transaction instructions are processed, the fee payer account balance will be deducted to pay for transaction fees. If the fee payer balance is not sufficient to cover transaction fees, the transaction will be dropped by the cluster. If the balance was sufficient, the fees will be deducted whether the transaction is processed successfully or not. In fact, if any of the transaction instructions return an error or violate runtime restrictions, all account changes _except_ the transaction fee deduction will be rolled back.
Before any transaction instructions are processed, the fee payer account balance
will be deducted to pay for transaction fees. If the fee payer balance is not
sufficient to cover transaction fees, the transaction will be dropped by the
cluster. If the balance was sufficient, the fees will be deducted whether the
transaction is processed successfully or not. In fact, if any of the transaction
instructions return an error or violate runtime restrictions, all account
changes _except_ the transaction fee deduction will be rolled back.
## Fee Distribution
Transaction fees are partially burned and the remaining fees are collected by the validator that produced the block that the corresponding transactions were included in. The transaction fee burn rate was initialized as 50% when inflation rewards were enabled at the beginning of 2021 and has not changed so far. These fees incentivize a validator to process as many transactions as possible during its slots in the leader schedule. Collected fees are deposited in the validator's account (listed in the leader schedule for the current slot) after processing all of the transactions included in a block.
Transaction fees are partially burned and the remaining fees are collected by
the validator that produced the block that the corresponding transactions were
included in. The transaction fee burn rate was initialized as 50% when inflation
rewards were enabled at the beginning of 2021 and has not changed so far. These
fees incentivize a validator to process as many transactions as possible during
its slots in the leader schedule. Collected fees are deposited in the
validator's account (listed in the leader schedule for the current slot) after
processing all of the transactions included in a block.