Skip to content
This repository has been archived by the owner on Aug 13, 2024. It is now read-only.

Propose KIP-162 Priority Fee Mechanism #162

Merged
merged 8 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions KIPs/kip-149.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Between the popular proxy patterns `Transparent` and `UUPS`, all system contract

### Definitions

- System contract: A contract that is read by the Klaytn core protocol or directly affect the protocol. The currently deployed system contracts are as follows: [**AddressBook**](https://github.com/klaytn/klaytn/blob/dev/contracts/reward/contract/AddressBook.sol), [**GovParam**](https://github.com/klaytn/klaytn/blob/dev/contracts/gov/GovParam.sol), **Voting**([KIP-81](https://github.com/klaytn/kips/blob/main/KIPs/kip-81.md)), **TreasuryRebalance**([KIP-103](https://github.com/klaytn/kips/blob/main/KIPs/kip-103.md))
- System contract: A contract that is read by the Klaytn core protocol or directly affect the protocol. The currently deployed system contracts are as follows: [**AddressBook**](https://github.com/klaytn/klaytn/blob/dev/contracts/contracts/system_contracts/consensus/AddressBook.sol), [**GovParam**](https://github.com/klaytn/klaytn/blob/dev/contracts/contracts/system_contracts/gov/GovParam.sol), **Voting**([KIP-81](https://github.com/klaytn/kips/blob/main/KIPs/kip-81.md)), **TreasuryRebalance**([KIP-103](https://github.com/klaytn/kips/blob/main/KIPs/kip-103.md))

- System contract upgrade: The process of updating an existing logic contract while maintaining a proxy contract. The upgraded logic contract must be compatible with the previous interface and its storage layout.

Expand Down Expand Up @@ -352,7 +352,7 @@ The existing system contracts will not be registered in the Registry, since they

## Implementation

- A reference implementation for the Registry contract: [Implementation](https://github.com/klaytn/klaytn/blob/dev/contracts/system_contracts/registry/Registry.sol)
- A reference implementation for the Registry contract: [Implementation](https://github.com/klaytn/klaytn/blob/dev/contracts/contracts/system_contracts/kip149/Registry.sol)
- A reference implementation for core logic: [Implementation](https://github.com/klaytn/klaytn/blob/dev/blockchain/system/registry.go)

## References
Expand Down
204 changes: 204 additions & 0 deletions KIPs/kip-162.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
---
kip: 162
title: Priority Fee Mechanism
author: Ollie (@blukat29), Sawyer (@2dvorak), Aidan (@aidan-kwon)
status: Draft
discussions-to: https://github.com/klaytn/kips/issues/161
type: Standard Track
category : Core
created: 2024-03-20
---

# Simple summary

Priority fee mechanism for transaction type 2 (EthereumDynamicFee) in terms of transaction ordering.

# Abstract

Activate the priority fee mechanism as defined in the EIP-1559. The maxPriorityFeePerGas field of transaction type 2 is no longer a placeholder, now it represents the priority fee the sender is willing to pay. The transactions are ordered by descending effective gas price, which is usually in the descending priority fee order. Under congested network, high priority transactions can be included to block by declaring high priority fee.

# Motivation

In Klaytn, the KIP-71 dynamic base fee mechanism and the FCFS (first come first serve) policy had been introduced to alleviate the network stability and usability issue caused by transaction bursts. However, if there are enough transactions that are willing to pay the upper bound base fee (e.g. 750 ston) then the network traffic will stay contested. Under such a condition, senders may experience transaction delay even if they pay the highest fee and send the transactions as soon as possible.

Raising the base fee upper bound is undesirable solution because the users no longer be able to predict or budget their gas fee spendings. Instead, this proposal adds a reliable method for urgent transactions to be included in blocks.

# Specification

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in [RFC-2119](https://www.ietf.org/rfc/rfc2119.txt).

## Block processing

### Configuration

The KIP-162 shall be activated since the `DRAGON_FORK_BLOCK_NUMBER`.

| config | value |
|-|-|
| `MAGMA_FORK_BLOCK_NUMBER` | 98347376 (testnet), 99841497 (mainnet) |
| `DRAGON_FORK_BLOCK_NUMBER` | TBD |

### Effective gas price and effective priority fee per gas

The effective gas price and effective priorirty fee per gas of a transaction at given block are calculated as follows. The effective gas price is the actual price of gas fee paid by the sender. The calculation differs by whether the transaction type is 2 (EIP-1559 EthereumDynamicFee) or not.

```py
def EffectiveGasPrice(header: Header, tx: Transaction):
if header.number >= DRAGON_FORK_BLOCK_NUMBER:
# Transaction type 2 has {maxFeePerGas, maxPriorityFeePerGas} fields
# Other transactions only have {gasPrice} field
if tx.type == 2:
maxFeePerGas = tx.maxFeePerGas
maxPriorityFeePerGas = tx.maxPriorityFeePerGas
else:
# makes EffectiveGasPrice() = tx.gasPrice
maxFeePerGas = tx.gasPrice
maxPriorityFeePerGas = tx.gasPrice
return min(header.baseFeePerGas + maxPriorityFeePerGas, maxFeePerGas)

elif header.number >= MAGMA_FORK_BLOCK_NUMBER:
return header.baseFeePerGas

else:
# Note: before Magma hardfork, transactions must satisfy
# tx.gasPrice == config.UnitPrice or tx.maxFeePerGas == config.UnitPrice.
# Therefore EffectiveGasPrice is essentially config.UnitPrice.
if tx.type == 2:
return tx.maxFeePerGas
else:
return tx.gasPrice

def EffectivePriorityFeePerGas(header: Header, tx: Transaction):
if header.number >= DRAGON_FORK_BLOCK_NUMBER:
effectiveGasPrice = EffectiveGasPrice(header, tx)
return effectiveGasPrice - header.baseFeePerGas
else:
return 0
```

### KIP-82 reward scheme

The [KIP-82](https://github.com/klaytn/kips/blob/main/KIPs/kip-82.md) reward scheme is slightly modified. The `get_total_fee` now accounts for effective gas price. Otherwise remains the same.

```py
def get_total_fee(header: Header, txs: list[Transaction], receipts: list[Receipt]):
# Note: EffectiveGasPrice handles hardfork
totalFee = 0
for i in range(len(txs)):
totalFee += EffectiveGasPrice(header, txs[i]) * receipts[i].gasUsed
return totalFee
```

### EVM GASPRICE opcode

The `GASPRICE` (0x3a) opcode returns the effective gas price of the currently executing transaction.

## Transaction pool

### Transaction ordering

Block transaction ordering depends on client implementation as the ordering is not checked by block validators. However, under the KIP-82 reward scheme, a proposer should prioritize high priority fee transactions for the maximum proposer reward.

Block proposers are recommended to order transactions with descending effective gas price, and the same effective gas price are sorted by transaction arrival time. This discourages the transaction spamming where a sender sends many transactions hoping that at least one is included in the block. Instead, the sender would pay a higher priority fee to ensure the transaction be included in the block.

### Txpool management

A transaction pool should not accept underpriced transactions. A transaction is underpriced if its `tx.gasPrice` or `tx.maxFeePerGas` field is lower than the baseFeePerGas of the pending block.

## JSON-RPC API

### `eth_gasPrice` and `klay_gasPrice`

Returns suggested value for `gasPrice` or `maxFeePerGas` fields of a transaction.

- Parameters: none
- Result: Recommended gas price in peb. The result depends on the client implementation.
- Example
```sh
curl $RPC_URL -X POST -H 'Content-Type: application/json' --data '
{"jsonrpc":"2.0","id":1,"method":"eth_gasPrice","params":[]}'

{"jsonrpc":"2.0","id":1,"result":"0xba43b7400"}
```

### `eth_maxPriorityFeePerGas` and `klay_maxPriorityFeePerGas`

Returns suggested value for `gasPrice` or `maxFeePerGas` fields of a transaction.

- Parameters: none
- Result: Recommended priority fee per gas in peb. The result depends on the client implementation.
- Example
```sh
curl $RPC_URL -X POST -H 'Content-Type: application/json' --data '
{"jsonrpc":"2.0","id":1,"method":"eth_maxPriorityFeePerGas","params":[]}'

{"jsonrpc":"2.0","id":1,"result":"0x3b9aca00"}
```

### `eth_feeHistory` and `klay_feeHistory`

Returns historical gas information for a range of blocks.

- Parameters
- `blockCount` - Number of blocks in the requested range.
- `newestBlock` - Highest block of the requested range. Can be a number or "latest".
- `rewardPercentiles` - (optional) A monotonically increasing list of percentile (between 0 and 100) values. For each block in the requested range, the transactions will be sorted in ascending order by effective tip per gas and sampled at the specified percentiles.
- Result
- `oldestBlock` - Lowest number block of returned range.
- `baseFeePerGas` - An array of block base fee per gas. This includes the next block after the newest of the returned range, because this value can be derived from the newest block. Zeroes are returned for pre-Magma blocks.
- `gasUsedRatio` - An array of block gas used ratios. Measures the network congestion level. These are calculated as the ratio of block gas used and [KIP-71 MAX_BLOCK_GAS_USED_FOR_BASE_FEE](https://github.com/klaytn/kips/blob/main/KIPs/kip-71.md). If the ratio is above 1, then 1 is returned.
- `reward` - (optional) A 2D array of effective priority fees per gas. `reward[n][i]` is the `rewardPercentiles[i]`-th percentile effective priority fees per gas among the transactions in the block `oldestBlock + n`. Only returned if `rewardPercentiles` is specified.
- Example
```sh
curl $RPC_URL -X POST -H 'Content-Type: application/json' --data '
{"jsonrpc":"2.0","id":1,"method":"eth_feeHistory","params":[
4,
"latest",
[50.0, 90.0, 95.0]
]}'

{
"id": "1",
"jsonrpc": "2.0",
"result": {
"oldestBlock": "0x8e0a025",
"baseFeePerGas": ["0x5d21dba00", "0x5d21dba00", "0x5d21dba00", "0x61c9f3680"],
"gasUsedRatio": [0.023, 0.31, 1.0, 0.88],
"reward": [
["0x3b9aca00", "0x3b9aca00", "0x9502f900"],
["0x3b9aca00", "0x3b9aca00", "0x9502f900"],
["0x3b9aca00", "0x9502f900", "0x2e90edd00"],
["0x3b9aca00", "0x9502f900", "0x30e4f9b40"],
]
}
}
```

# Rationale

## A KIP-71 parameter is used in place of block gas limit

The Ethereum's `eth_feeHistory` calculates gasUsedRatio as `block.gasUsed/blockGasLimit`. But Klaytn does not have hard limit of block gas. Instead, Klaytn's MAX_BLOCK_GAS_USED_FOR_BASE_FEE is analogous to Ethereum's block gas limit.

In Ethereum, block gas limit is 30,000,000 and the base fee starts to rise when the block gas used exceeds 15,000,000 (`block.gasLimit / ELASTICITY_MULTIPLIER`). Similartly, the Klaytn's initial KIP-71 parameters stipulates that the block gas used is only accounted until 60,000,000 for the purpose of base fee calculation (`MAX_BLOCK_GAS_USED_FOR_BASE_FEE`), and the base fee starts to rise when the block gas used exceeds 30,000,000 (`GAS_TARGET`).

# Backward compatibility

## Continued use of other transaction types

Legacy (type 0) transactions, EIP-2930 AccessList (type 1) transactions, and Klaytn transaction types (types 8+) will work and be included in blocks. Those transactions have `gasPrice` field but no `maxFeePerGas` nor `maxPriorityFeePerGas` fields. For those transaction types, their effective gas price is considered to equal to the `gasPrice`. The senders pay the full price as declared in the `gasPrice`. This policy is identical to [EIP-1559](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md) and the same as pre-1559 auction market. In this manner, those transaction types pay a nonzero priority fee.

| baseFeePerGas | transaction | effectiveGasPrice | effectivePriorityFeePerGas |
|-|-|-|-|
| 25 | {type: 0, gasPrice: 26} | 26 | 1 |
| 25 | {type: 2, maxFeePerGas: 51, maxPriorityFeePerGas: 1} | 26 | 1 |

## EVM opcodes

The `GASPRICE` (0x3a) opcode is backwards compatible because it had been correctly returning the effective gas price before `DRAGON_FORK_BLOCK_NUMBER`. The `BASEFEE` (0x48) opcode remains the same; returns the base fee per gas of the currently executing block.

# References

- https://github.com/klaytn/kips/blob/main/KIPs/kip-71.md
- https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md
- https://github.com/ethereum/execution-apis/blob/main/src/eth/fee_market.yaml
Loading