Part 1: Decoding Ethereum dApp Development: Nonce, Gas, and Fees Explained
Simplifying key concepts in EVM blockchain development: Nonce, Gas, Gas Limit, Gas Price, maxFeePerGas, maxPriorityFeePerGas.
You are finally there. Building your first dApp. Ethereum is the platform of your choice, so you have done your research already and performed some transactions. But, sometimes, there were some issues with broadcasting your transaction to the node. It got stuck or, even worse, didn't appear in the blockchain at all. You don't know why; you have done everything correctly.
I know how you feel. I have been there. There are a lot of things that could go wrong, and I will try to explain each one of them step by step so you will never make the same mistake again. So, get ready. πππ
I will cover some of the key concepts of working with transactions on EVM blockchains.
nonce
gas consumed by transaction
gasLimit set to transaction
gasPrice of the gas unit
maxFeePerGas and maxPriorityFeePerGas of the gas unit - new EIP-1559 standard
Nonce
One of the biggest problems, or unknowns, in the EVM world. Everyone is struggling with nonce management because this is the key component when you want to scale your transaction throughput. But let's start with the explanation.
When you are preparing your transaction, you must specify the nonce. Some blockchain SDKs specify the nonce automatically by reading it from the blockchain node.
But this is where problems arise.
Transaction was sent but is not visible in the explorer
One of the common problems you might face is the non-visibility of the transaction. Everything seems perfect - the transaction was prepared, signed, and broadcasted correctly, but it doesn't appear in the block. Never. Blockchain explorers can't see it. This happens when you use the wrong nonce. The nonce must be used in order, the latest successfully used nonce +1, starting from 0. Anything else will be buried inside the mempool of the blockchain node you have used for broadcasting the transaction and dropped after some time. By that time, you have very limited ways to fix this. Usually, you must send a transaction with the proper nonce and a higher fee than the false one.
Transaction was sent, but it's stuck in the explorer
Your transaction is visible in the Explorer, but the fee you have provided is so low that it can't be included in the block. Your transaction is basically stuck and pending. You have two options how to manage this:
Wait for a lower fee so your transaction will be unblocked
Resend the same transaction with the same nonce but a higher fee
I will cover this topic in more depth in the following posts.
Sending huge amounts of transactions in a short period of time
Your dApp is exploding, and you need to send a huge amount of transactions from the same address in a short period of time. There are multiple scenarios that could happen:
You are using a blockchain RPC provider, where you can access a pool of nodes hidden behind the load balancer. Whenever you want to perform a transaction, you read the latest nonce from the node. The problem is that your request might hit different nodes, and those nodes are not synced with each other fast enough, so you can get different nonce from different nodes. This will result in your transaction being stuck in one of the mempool of the nodes because one mempool sees a different nonce based on its state than the one you used to create your transaction.
You are using a dedicated RPC node. You always get the correct nonce every time you ask for it, and your transactions are being accepted by the node. But, for some reason, one of the transactions is stuck with a lower fee in the mempool. All other transactions sent after that stuck one are being stuck in the mempool as well because their order must be guaranteed. You can again replace the original one with the higher fee and speed it up.
You are maintaining your own nonce counter in your application. You are 100% dependent on your app logic, and you must double-check if every transaction you have broadcasted actually hits the node and is included in the block.
Summary
There is no easy way out of the nonce issues. The most important thing is that you actually understand the problem, and you are aware of what might happen and what are the corner cases. I personally prefer approach number 2, where you are hitting a dedicated node with all the read nonce requests and transaction broadcasts. It will guarantee you the same answers. You are not relying on syncing of mempools between multiple nodes. The worst scenario is that some of your transactions might be stuck if you don't do your fee management right. That's something I will cover in the next post. Stay tuned.