Tempo Mainnet is now live on Chainstack! Get Tempo RPC endpoint for free!    Learn more
  • Pricing
  • Docs

EVM: Practical explanation of how gas fee works

Created Dec 11, 2025 Updated Dec 11, 2025

Intro

You broadcast a transaction on Ethereum (or any EVM network) using tools like web3.js or ethers.js, expecting it to be included in the network, but… nothing happens. After seconds or even minutes, you finally get the error: Transaction Was Not Mined Within N Blocks. Your transaction is stuck. Why? What happens to it now? How can you get it mined? How to prevent such cases next time? This article explains what goes on behind the scenes, walking through all the concepts needed to fully understand the issue and the solutions. Gas fees matter so much that Vitalik recently suggested creating a gas futures market! By the end of this article you’ll see he probably wasn’t kidding.

TL;DR

Your transaction gets stuck and eventually errors with “not mined within N blocks” when the priority fee (tip) you offered validators is too low compared to competing transactions. EIP-1559 splits the fee into a dynamically adjusting baseFeePerGas (burned) and a priorityFeePerGas (goes to validator). If priorityFeePerGas is too small, validators ignore your transaction. Fix it by sending a new transaction with the same nonce and higher fees (speed-up) or 0 ETH to yourself (cancel).

Why “Not Mined Within N Blocks” Happens

You prepared everything, created and signed a transaction, and sent it on-chain, but you received an error like this:

Transaction started at 78840812 but was not mined within 61 blocks. Please make sure your transaction was properly sent and there are no previous pending transactions for the same account. However, be aware that it might still be mined!
	Transaction Hash: 0xdbf108…

Why wasn’t the transaction included in a block on time?

Short answer: The transaction wasn’t a priority for validators, so they preferred transactions that were worth more to them. When a transaction is sent to the network, it first goes into the mempool, a pool full of transactions pending for confirmation. To put it simply, validators choose the most profitable transactions to include in the block, and the least profitable ones get stuck in the mempool, like yours did.

Yh5baeaaaaalaaaaaabaaeaaaibraa7 logo

In today’s Ethereum, most validators don’t pick transactions themselves. Instead, they use MEV-Boost to outsource block building to specialized builders who compete in auctions to build the most profitable blocks possible. Many transactions also skip the public mempool entirely by going privately to these builders (e.g., via Flashbots Protect). We’ll cover MEV-Boost and private mempools in upcoming articles.

What determines a transaction’s priority for validators?

Each transaction requires some work by network resources, and pays a fee for each unit of work it requires. The fee is shared between the network and the validator. The higher the fee paid to the validator per unit of work, the higher the transaction’s priority. This leads to three key questions:

  • What determines the amount of work a transaction requires?
  • What determines the cost per unit of work?
  • How is the fee distributed between network and validator?

What determines the amount of work a transaction requires?

Every transaction consumes network resources like computation, storage, etc. Standards define exactly how much work each operation requires. This work is measured in units called Gas. To get a feel for gas costs, here are a few real examples:

  • Adding two numbers: 5 gas
  • Storing 1 KB of data on-chain: ~700,000 gas
  • Base transaction cost (signature verification, account state updates, nonce increment, and network overhead): 21,000 gas 

Although the amount of gas consumed by a transaction can be estimated in advance, the exact amount is only known after it has been fully executed by validators, as it depends on factors like network state that can change with every block. When broadcasting a transaction, a parameter called gasLimit must be specified. The gasLimit defines the maximum amount of gas the transaction is allowed to consume. Two major cases might happen after executing a transaction:

  • Final used gas is less than gasLimit: the remaining gas won’t be used. Transaction only pays for the gas it consumes.
  • Transaction tries to consume more than the gasLimit: It fails with an  out of gas error, all state changes are reverted, yet the transaction is still included and the full gasLimit is charged.

The gasLimit should be set high enough to cover the worst-case consumption (typically 10–20 % above the estimate). If set too high, nothing is lost. You are never charged for unused gas. If set too low, the transaction fails without reducing the actual cost.

What determines the cost per unit of work?

The previous section explained how gas usage of a transaction is specified and controlled. Now the focus is on determining how much fee a transaction is willing to pay per gas. Once this value –the price of each gas unit, called feePerGas– is determined, the total fee calculation is simple:

totalFee = gasUsed * feePerGas

As mentioned earlier, feePerGas consists of two parts: network fee and validator fee. Network fee, called baseFeePerGas, is calculated based on how full the last block was. When more transactions are competing to be mined, baseFeePerGas rises. On the other hand, when the previous block wasn’t as full, baseFeePerGas drops. So baseFeePerGas is the same for all transactions in a block, and cannot be set individually per transaction.

Now let’s get to the validator fee, called the priority fee. The name explains it: higher priority fee directly increases a transaction’s chance of being included. The logic is clear:

totalFee = gasUsed * feePerGas
feePerGas = BaseFeePerGas + PriorityFeePerGas
→ totalFee = gasUsed * (BaseFeePerGas + PriorityFeePerGas)

How is the fee distributed between network and validator?

The answer lies in two values that must be specified when broadcasting a transaction: maxFeePerGas and maxPriorityFeePerGas. The logic becomes clearer once you look at the variables together.

baseFeePerGas is determined by the network, and maxFeePerGas is set in the transaction. The difference becomes the priorityFeePerGas, with maxPriorityFeePerGas as a ceiling.

PriorityFeePerGas = min(maxPriorityFeePerGas, maxFeePerGas - BaseFeePerGas)

In summary: A transaction specifies two ceilings, one for total fee and one for priority fee. By default, the maximum priority fee is charged for validators, and the base fee is burned by the network. But if the base fee rises so that base fee + max priority fee would exceed the total fee cap, the priority fee is lowered to keep the sum within the limit.

Yh5baeaaaaalaaaaaabaaeaaaibraa7 logo

All of these lead to the key point: this is how priorityFeePerGas gets calculated. When a transaction is stuck in the mempool, it’s because priorityFeePerGas is too low, which results directly from one of these two:

  • maxPriorityFeePerGas is set too low
  • Many new transactions arrived in the mempool, increasing baseFeePerGas and reducing maxFeePerGasbaseFeePerGas.

What happens to transactions stuck in the mempool?

There are three main possible outcomes:

  1. Transaction gets dropped from the mempool: If maxFeePerGas falls below baseFeePerGas, the transaction gets dropped. Additionally, different nodes have different expiration times, after which they drop the transaction from their mempool.
  2. Transaction gets mined before being dropped: When network congestion drops and the base fee falls, validators will pick up even low priority fee transactions.
  3. The sender either cancels the transaction or speeds up its mining.

Since options 1 and 2 are unpredictable, developers typically prefer option3, so let’s see how it is done.

How to cancel a stuck transaction or speed up its mining?

Fortunately, fixing a stuck transaction is straightforward.

Speed up: Send the same transaction with the same nonce but higher values for:

  • maxFeePerGas: if the network’s baseFeePerGas has increased
  • and/or maxPriorityFeePerGas: if it was set too low compared to competing mempool transactions.

Cancel: Send a 0-ETH transaction to yourself using the same nonce and slightly higher fees.

Yh5baeaaaaalaaaaaabaaeaaaibraa7 logo

Conclusion

Understanding EVM gas mechanics is essential for every Ethereum developer. Mastering these fundamentals lets you set the right fees from the start, avoid stuck transactions, instantly fix them with speed-ups or cancels when needed, and prevent unnecessary overpayment during congestion spikes while keeping transactions reliably fast and smooth.

Reliable Ethereum RPC infrastructure

Getting started with Ethereum on Chainstack is fast and straightforward. Developers can deploy a reliable Ethereum node within seconds through an intuitive Console — no complex setup or hardware management required. 

Chainstack provides low-latency Ethereum RPC access, ensuring seamless connectivity for building, testing, and scaling DeFi, analytics, and trading applications. With Ethereum low-latency endpoints powered by global infrastructure, you can achieve lightning-fast response times and consistent performance across regions. 

Start for free, connect your app to a reliable Ethereum RPC endpoint, and experience how easy it is to build and scale on Ethereum with Chainstack – one of the best RPC providers.

SHARE THIS ARTICLE
Cham

Chamrun Moeini

Software engineer with a focus on blockchain. All about solving meaningful problems and bringing more freedom and simplicity to everyday users. Interested in whatever it takes to make that real, from Web3, DeFi and interoperability to software design and product engineering.

Customer Stories

tendex

Multi-contract stress-testing to ensure smooth trading infrastructure mainnet operations.

Aleph One

Operate smarter and more efficiently with seamless integration of decentralized applications.

Kenshi Oracle Network

Contributing towards a swifter Web3 for all with secure, efficient, and robust oracle infrastructure.