1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0
// Copyright 2021 Conflux Foundation. All rights reserved.
// Conflux is free software and distributed under GNU General Public License.
// See http://www.gnu.org/licenses/
#![forbid(unsafe_code)]
// Increase recursion limit to allow for use of select! macro.
//! Mempool is used to hold transactions that have been submitted but not yet
//! agreed upon and executed.
//!
//! **Flow**: AC sends transactions into mempool which holds them for a period
//! of time before sending them into consensus. When a new transaction is
//! added, Mempool shares this transaction with other nodes in the system. This
//! is a form of “shared mempool” in that transactions between mempools are
//! shared with other validators. This helps maintain a pseudo global ordering
//! since when a validator receives a transaction from another mempool, it will
//! be ordered when added in the ordered queue of the recipient validator. To
//! reduce network consumption, in “shared mempool” each validator is
//! responsible for delivery of its own transactions (we don't rebroadcast
//! transactions originated on a different peer). Also we only broadcast
//! transactions that have some chance to be included in next block: their
//! sequence number equals to the next sequence number of account or sequential
//! to it. For example, if the current sequence number for an account is 2 and
//! local mempool contains transactions with sequence numbers 2,3,4,7,8, then
//! only transactions 2, 3 and 4 will be broadcast.
//!
//! Consensus pulls transactions from mempool rather than mempool pushing into
//! consensus. This is done so that while consensus is not yet ready for
//! transactions, we keep ordering based on gas and consensus can let
//! transactions build up. This allows for batching of transactions into a
//! single consensus block as well as prioritizing by gas price. Mempool doesn't
//! keep track of transactions that were sent to Consensus. On each get_block
//! request, Consensus additionally sends a set of transactions that were pulled
//! from Mempool so far but were not committed yet. This is done so Mempool can
//! be agnostic about different Consensus proposal branches. Once a transaction
//! is fully executed and written to storage, Consensus notifies Mempool about
//! it which later drops it from its internal state.
//!
//! **Internals**: Internally Mempool is modeled as `HashMap<AccountAddress,
//! AccountTransactions>` with various indexes built on top of it. The main
//! index `PriorityIndex` is an ordered queue of transactions that are “ready”
//! to be included in next block(i.e. have sequence number sequential to current
//! for account). This queue is ordered by gas price so that if a client is
//! willing to pay more (than other clients) per unit of execution, then they
//! can enter consensus earlier. Note that although global ordering is
//! maintained by gas price, for a single account, transactions are ordered by
//! sequence number.
//!
//! All transactions that are not ready to be included in the next block are
//! part of separate `ParkingLotIndex`. They will be moved to the ordered queue
//! once some event unblocks them. For example, Mempool has transaction with
//! sequence number 4, while current sequence number for that account is 3. Such
//! transaction is considered to be “non-ready”. Then callback from Consensus
//! notifies that transaction was committed(i.e. transaction 3 was submitted to
//! different node). Such event “unblocks” local transaction and txn4 will be
//! moved to OrderedQueue.
//!
//! Mempool only holds a limited number of transactions to prevent OOMing the
//! system. Additionally there's a limit of number of transactions per account
//! to prevent different abuses/attacks
//!
//! Transactions in Mempool have two types of expirations: systemTTL and
//! client-specified expiration. Once we hit either of those, the transaction is
//! removed from Mempool. SystemTTL is checked periodically in the background,
//! while the client-specified expiration is checked on every Consensus commit
//! request. We use a separate system TTL to ensure that a transaction won't
//! remain stuck in Mempool forever, even if Consensus doesn't make progress
//#[cfg(any(test, feature = "fuzzing"))]
//mod tests;
pub use shared_mempool::{
bootstrap, network,
types::{
gen_mempool_reconfig_subscription, CommitNotification, CommitResponse,
CommittedTransaction, ConsensusRequest, ConsensusResponse,
MempoolClientSender, SubmissionStatus, TransactionExclusion,
},
};
//#[cfg(any(test, feature = "fuzzing"))]
//pub use tests::{fuzzing, mocks};
mod core_mempool;
mod counters;
mod logging;
mod shared_mempool;