KIP 162: Priority Fee Mechanism Source

AuthorOllie, Sawyer, Aidan
Discussions-Tohttps://github.com/klaytn/kips/issues/161
StatusDraft
TypeStandard Track
CategoryCore
Created2024-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.

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.

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 reward scheme is slightly modified. The get_total_fee now accounts for effective gas price. Otherwise remains the same.

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
    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
    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. 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
    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 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