-
Notifications
You must be signed in to change notification settings - Fork 86
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
78 additions
and
1 deletion.
There are no files selected for viewing
79 changes: 78 additions & 1 deletion
79
ouroboros-consensus/docs/report/chapters/storage/mempool.tex
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,84 @@ | ||
\chapter{Mempool} | ||
\label{mempool} | ||
|
||
Whenever a block producing node is the leader of a slot | ||
(\cref{consensus:class:leaderselection}), it gets the chance to mint a block. | ||
For the Cardano blockchain to be useful, the minted block in the blockchain | ||
needs to contain \emph{transactions}. The \emph{mempool} is where we buffer | ||
transactions until we are able to mint a block containing those transactions. | ||
|
||
Transactions created by the user using the wallet enter the Mempool via the | ||
local transaction submission protocol (see \cref{servers:txsubmission}). As not | ||
every user will be running a block producing node or stakepool, these | ||
transactions should be broadcast over the network so that other, block | ||
producing, nodes can include these transactions in their next block, in order | ||
for the transactions to ends up in the blockchain as soon as possible. This is | ||
accomplished by the node-to-node transaction submission protocol\todo{link?}, | ||
which exchanges the transactions between the mempool of the nodes in the | ||
network. | ||
|
||
Naturally, we only want to put transactions in a block that are valid | ||
w.r.t.\ the ledger state against which the block will be applied. Putting | ||
invalid transactions in a block will result in an invalid block, which will be | ||
rejected by other nodes. Consequently, the block along with its rewards is lost. | ||
Even for a node that is not a block producer, there is no point in flooding the | ||
network with invalid transactions. For these reasons, we validate the | ||
transactions in the mempool w.r.t.\ the current ledger state and remove | ||
transactions that are no longer valid. | ||
|
||
\section{Consistency} | ||
\label{mempool:consistency} | ||
|
||
Discuss that we insist on \emph{linear consistency}, and why. | ||
Transactions themselves affect the ledger state, consequently, the order in | ||
which transactions are applied matters. For example, two transactions might try | ||
to consume the same UTxO entries. The first of the two transactions to be | ||
applied determines will be valid, the second will be invalid. Transactions can | ||
also depend on each other, hence the transactions that are depended upon should | ||
be applied first. Consequently, the mempool needs to decide how transactions are | ||
ordered. | ||
|
||
We chose a simple approach: we maintain a list of transactions, ordered by the | ||
time at which they arrived. This has the following advantages: | ||
|
||
\begin{itemize} | ||
\item It's simple to implement and it's efficient. In particular, no search for | ||
a valid subset is ever required. | ||
\item When minting a block, we can simply | ||
take the longest possible prefix of transactions that fits in a block. | ||
\item It supports wallets that submit dependent transactions (where later | ||
transaction depends on outputs from earlier ones). | ||
\end{itemize} | ||
|
||
We call this \emph{linear consistency}: transactions are ordered linearly and | ||
each transaction is valid w.r.t.\ the transactions before it and the ledger | ||
state against which the mempool was validated. | ||
|
||
The mempool has a background thread that watches the current ledger state | ||
exposed by the Chain DB (\cref{chaindb}). Whenever it changes, the mempool will | ||
revalidate its contents w.r.t.\ that ledger state. This ensures that we no | ||
longer keep broadcasting invalid transactions and that the next time we get to | ||
mint a block, we do not have to validate a bunch of invalid transactions, | ||
costing us more crucial time. | ||
|
||
\section{Caching} | ||
|
||
The mempool caches the ledger state resulting from applying all the transactions | ||
in the mempool to the current ledger state. This makes it quick and easy to | ||
validate incoming transactions, they can simply be validated against the cached | ||
ledger state without having to recompute it for each transaction. As discussed | ||
in \cref{ledgerdb:in-memory}, the memory cost of this is minimal. When the | ||
incoming transaction is valid w.r.t.\ the cached ledger state, we append the | ||
transaction to the mempool and we cache the resulting ledger state. | ||
|
||
\todo{TODO} talk about the slot for which we produce | ||
|
||
\section{TxSeq} | ||
|
||
\todo{TODO} efficiently get the first $x$ transactions that fit into the given size | ||
|
||
\todo{TODO} discuss \lstinline!TicketNo! | ||
|
||
\section{Capacity} | ||
|
||
\todo{TODO} discuss dynamic capacity, based on twice the max block (body?) size in the protocol parameters in the ledger | ||
\todo{TODO} add transactions one-by-one for better concurrency and fewer revalidation in case of retries |