The mem-pool is where transactions wait to be inserted into a block. Each block producer node needs to maintain its mem-pool. Having control over the mem-pool is an advantage that can be abused. In the article, you will learn what mem-pool is used for. We will explain how a front-running attack works.
What is Mem-Pool?
In a distributed network, there is no central point that controls the production of blocks. In the Cardano network, one node (slot leader) is randomly elected approximately every 20 seconds and gets the right to mint a new block. Block producers (or pools) are located all over the world and a new pool can be launched at any time and anywhere.
When a user submits a transaction to the network, it must reach all pools. This is because it is not known in advance which slot leader will be drawn in the next round. In the ideal case, the transaction reaches all nodes, so there is a chance that the next slot leader will insert it into a new block.
At any given moment, users around the world are submitting transactions. Nodes validate transactions, but that's the only thing they can do with them at a given moment. If the transactions are valid, they have to wait somewhere before being inserted into a new block.
The mem-pool serves as a sort of waiting room for transactions before they are added to the ledger.
You can think of a mem-pool as a temporary memory on each node where transactions are temporarily stored before they get into the block. Once transactions get into the block, they will be stored in the ledger forever (unless the blockchain is reorganized).
Each pool (node) can have a different composition of the mem-pool because they receive transactions in a different order.
If Alice from Europe, Bob from the US, and Carol from China submit transactions at the same time, nodes in different parts of the world will receive the transactions in a different order.
In the figure, you can see 3 users who submitted a transaction at the same time. Each user used a different node (because, for example, they used a different light wallet). Each transaction reached the nearest node, which inserted it into its mem-pool. Nodes then broadcast the transaction to peers. Depending on the quality of the network connection, transactions arrive at peers very likely in a different order. Peer nodes validate transactions and put them in the mem-pool where other transactions are already waiting. As you can see, each mem-pool looks different. All mem-pools contain all the transactions that were submitted but in a different order.
For simplicity, relay nodes are not shown in the figure.
Transactions are available in the mem-pool on all nodes, so it doesn't matter which one becomes the next slot leader. If the transactions fit into the new block, they will all be inserted into it.
In the figure, you can see that node 1 was elected as slot leader. Node 1 takes all transactions from the mem-pool and inserts them into a new block. Node 1 mints a new block and adds it to its ledger. Node 1 broadcasts the block to peers (node 2 and node 3). Peers don't know about the new block yet, so the transactions are still in their mem-pool.
In the figure, you can see that node 2 and node 3 received a new block from node 1. Nodes 2 and 3 validated the block and added it to their ledger. During this process, these nodes deleted from the mem-pool those transactions that were in the new block. Note that users have submitted new transactions in the meantime. Those transactions that are already in the ledger have been deleted from all mem-pools. However, the mem-pool is constantly being filled with new transactions.
In the last figure, all nodes have the same ledger state, but a different order of transactions in the mem-pools. In the next round, a new slot leader will be elected and the whole process will be repeated.
Before anything can be written on a block, it must first move through the mem-pool. It's an integral part of how a blockchain node functions. The same thing that happens with transactions also applies to certificates (delegation certificates, pool registration certificates, etc.). When validating transactions, scripts may be executed.
The mem-pool stores candidate transactions (in a local memory) before they are inserted into a new block. Each node attempts to remain synchronized with other nodes over the network. Since network communication is not always reliable or timely, each node has a slightly (or sometimes significantly) different mem-pool. Nodes queue transactions according to the order in which they arrive.
The mem-pool works as a kind of network buffer. If it is not possible to put all transactions into a new block, the transactions can wait in the mem-pool. But only up to a fixed limit. The mem-pool size is not significantly larger than the block size. Ideally, the mem-pool should remain empty after a new block is minted.
Transactions leave a node's mem-pool because they are included in a block. The mem-pool may reach full capacity. In this case, it is not possible to accept newly arrived transactions. This is a back-pressure mechanism. Users may experience that their transaction is not accepted by the network. They must try to resubmit the transaction again after some time (or a wallet/agent can do it for them).
Currently, the size of the mem-pool is 145 kb. The block size is 90 kb. A typical transaction is roughly 300 bytes. About 500 common transactions can fit into the mem-pool.
The goal of the mem-pool is not to store all submitted transactions in case the network is overloaded. The goal of the mem-pool is to hold a large enough number of transactions for a new block. In other words, to ensure the maximum possible throughput. Increasing the mem-pool cannot solve low scalability.
In general, bigger mem-pools just create more work and bigger latency. Cardano is designed not to buffer many transactions but to put back pressure on the edges of the system. This seems to be a better approach than using big mem-pools since it provides better feedback, and uses fewer resources to manage pending work.
Each node operator controls its mem-pool. However, no one has control over the mem-pools of other operators. Transactions in the mem-pool are not encrypted. The pool operator can analyze them. It is even possible to publish the transactions of one's mem-pool.
Having control over the mem-pool can be an advantage. Especially in the case that a specific node is the gateway for user transactions. The operator can identify a specific transaction and its impact on the ledger in case the transaction is inserted into a new block.
The fraudulent operator can delay the user's transaction and insert his transaction in front of it. The attacker's transaction will have similar parameters to the user's transaction. He can profit from it. A user may want to make some profitable trade on DEX. The operator can hold the user's transaction and quickly submit his transaction. The fraudulent transaction reaches the other mem-pools before the user's transaction. The operator will thus make a profitable trade in front of the user.
In the figure, you can see that the user submitted transaction T1 at time N. The operator analyzed the transaction before inserting it into his mem-pool and broadcasting it to peers. He evaluated that this is a profitable trade. Therefore, at time N+1 (a bit later), he submitted (fraudulent) transaction T0 and broadcast it to the network before the user transaction. Peers receive transaction T0 first and then T1. Node 2 already has transactions in the mem-pool. Node 3 receives transactions in the order chosen by the operator of node 1.
Users should think more about the node through which their transaction is submitted to the network. However, any node operator in the figure above can theoretically attempt a similar front-running attack. So the operator of nodes 2 and 3.
If the operator of node 1 was honest and did not want to commit a front-running attack, the user's transaction would be broadcast to the network. If the operators of nodes 2 and 3 wanted to commit a front-running attack, it would be more difficult for them, because the user transaction would have already reached the part of the nodes in the network (which will broadcast it again). The success of the attack would be a matter of chance and it would depend on which node is elected as the slot leader in the next round.
Having a high number of block producer nodes in the network can potentially help mitigate front-running attacks (and transaction censorship). This is because the more decentralized the network is, the harder it becomes for a single entity to control or manipulate transaction order. However, it is important to note that this measure alone may not be sufficient to completely prevent such attacks.
In Cardano, transaction fees are not used as a decision factor for including transactions in a block. This means that users (including pool operators) cannot pay higher fees to prioritize their transactions.
This design can make front-running attacks more difficult compared to networks that use a fee market concept. In networks using the fee market, users can pay higher fees to have their transactions processed more quickly, which can potentially be exploited by attackers.
Operators see user transactions and can choose which ones to insert into a new block if they become slot leaders, but they cannot steal users' assets. However, they can manipulate transactions in their favor. For example, slow down their broadcasts to peers.
Understanding the function of the mem-pool is important in the context of the transaction lifecycle. There are two important periods between submitting a transaction and the time it becomes immutable: transaction latency and transaction finality.
Transaction latency is the time between when a transaction is submitted and when it appears in the ledger (in a new block). Transaction finality is the time between appearing in the first block until the transaction is immutable. A transaction will be immutable as soon as there is a sufficient number of newly appended blocks behind the block that contains it (at least 5).