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;