Skip to content

Commit

Permalink
report: Start the Mempool chapter
Browse files Browse the repository at this point in the history
  • Loading branch information
mrBliss committed Jan 15, 2021
1 parent ea72d29 commit f2a027d
Showing 1 changed file with 78 additions and 1 deletion.
79 changes: 78 additions & 1 deletion ouroboros-consensus/docs/report/chapters/storage/mempool.tex
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

0 comments on commit f2a027d

Please sign in to comment.