Skip to content

Commit cf5f1fa

Browse files
committed
MOVEONLY: DisconnectedBlockTransactions to its own file
This struct is only used in validation + tests and has very little to do with txmempool.
1 parent 2765d6f commit cf5f1fa

File tree

6 files changed

+133
-115
lines changed

6 files changed

+133
-115
lines changed

src/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ BITCOIN_CORE_H = \
186186
kernel/coinstats.h \
187187
kernel/context.h \
188188
kernel/cs_main.h \
189+
kernel/disconnected_transactions.h \
189190
kernel/mempool_entry.h \
190191
kernel/mempool_limits.h \
191192
kernel/mempool_options.h \

src/bench/disconnected_transactions.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
44

55
#include <bench/bench.h>
6+
#include <kernel/disconnected_transactions.h>
7+
#include <primitives/block.h>
68
#include <test/util/random.h>
79
#include <test/util/setup_common.h>
8-
#include <validation.h>
910

1011
constexpr size_t BLOCK_VTX_COUNT{4000};
1112
constexpr size_t BLOCK_VTX_COUNT_10PERCENT{400};
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// Copyright (c) 2023 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#ifndef BITCOIN_KERNEL_DISCONNECTED_TRANSACTIONS_H
6+
#define BITCOIN_KERNEL_DISCONNECTED_TRANSACTIONS_H
7+
8+
#include <core_memusage.h>
9+
#include <memusage.h>
10+
#include <primitives/transaction.h>
11+
#include <util/hasher.h>
12+
13+
#include <list>
14+
#include <unordered_map>
15+
16+
/**
17+
* DisconnectedBlockTransactions
18+
19+
* During the reorg, it's desirable to re-add previously confirmed transactions
20+
* to the mempool, so that anything not re-confirmed in the new chain is
21+
* available to be mined. However, it's more efficient to wait until the reorg
22+
* is complete and process all still-unconfirmed transactions at that time,
23+
* since we expect most confirmed transactions to (typically) still be
24+
* confirmed in the new chain, and re-accepting to the memory pool is expensive
25+
* (and therefore better to not do in the middle of reorg-processing).
26+
* Instead, store the disconnected transactions (in order!) as we go, remove any
27+
* that are included in blocks in the new chain, and then process the remaining
28+
* still-unconfirmed transactions at the end.
29+
*
30+
* Order of queuedTx:
31+
* The front of the list should be the most recently-confirmed transactions (transactions at the
32+
* end of vtx of blocks closer to the tip). If memory usage grows too large, we trim from the front
33+
* of the list. After trimming, transactions can be re-added to the mempool from the back of the
34+
* list to the front without running into missing inputs.
35+
*/
36+
class DisconnectedBlockTransactions {
37+
private:
38+
/** Cached dynamic memory usage for the CTransactions (memory for the shared pointers is
39+
* included in the container calculations). */
40+
uint64_t cachedInnerUsage = 0;
41+
std::list<CTransactionRef> queuedTx;
42+
using TxList = decltype(queuedTx);
43+
std::unordered_map<uint256, TxList::iterator, SaltedTxidHasher> iters_by_txid;
44+
45+
public:
46+
// It's almost certainly a logic bug if we don't clear out queuedTx before
47+
// destruction, as we add to it while disconnecting blocks, and then we
48+
// need to re-process remaining transactions to ensure mempool consistency.
49+
// For now, assert() that we've emptied out this object on destruction.
50+
// This assert() can always be removed if the reorg-processing code were
51+
// to be refactored such that this assumption is no longer true (for
52+
// instance if there was some other way we cleaned up the mempool after a
53+
// reorg, besides draining this object).
54+
~DisconnectedBlockTransactions() {
55+
assert(queuedTx.empty());
56+
assert(iters_by_txid.empty());
57+
assert(cachedInnerUsage == 0);
58+
}
59+
60+
size_t DynamicMemoryUsage() const {
61+
return cachedInnerUsage + memusage::DynamicUsage(iters_by_txid) + memusage::DynamicUsage(queuedTx);
62+
}
63+
64+
/** Add transactions from the block, iterating through vtx in reverse order. Callers should call
65+
* this function for blocks in descending order by block height.
66+
* We assume that callers never pass multiple transactions with the same txid, otherwise things
67+
* can go very wrong in removeForBlock due to queuedTx containing an item without a
68+
* corresponding entry in iters_by_txid.
69+
*/
70+
void AddTransactionsFromBlock(const std::vector<CTransactionRef>& vtx)
71+
{
72+
iters_by_txid.reserve(iters_by_txid.size() + vtx.size());
73+
for (auto block_it = vtx.rbegin(); block_it != vtx.rend(); ++block_it) {
74+
auto it = queuedTx.insert(queuedTx.end(), *block_it);
75+
iters_by_txid.emplace((*block_it)->GetHash(), it);
76+
cachedInnerUsage += RecursiveDynamicUsage(**block_it);
77+
}
78+
}
79+
80+
/** Remove any entries that are in this block. */
81+
void removeForBlock(const std::vector<CTransactionRef>& vtx)
82+
{
83+
// Short-circuit in the common case of a block being added to the tip
84+
if (queuedTx.empty()) {
85+
return;
86+
}
87+
for (const auto& tx : vtx) {
88+
auto iter = iters_by_txid.find(tx->GetHash());
89+
if (iter != iters_by_txid.end()) {
90+
auto list_iter = iter->second;
91+
iters_by_txid.erase(iter);
92+
cachedInnerUsage -= RecursiveDynamicUsage(**list_iter);
93+
queuedTx.erase(list_iter);
94+
}
95+
}
96+
}
97+
98+
/** Remove the first entry and update memory usage. */
99+
CTransactionRef take_first()
100+
{
101+
CTransactionRef first_tx;
102+
if (!queuedTx.empty()) {
103+
first_tx = queuedTx.front();
104+
cachedInnerUsage -= RecursiveDynamicUsage(*queuedTx.front());
105+
iters_by_txid.erase(queuedTx.front()->GetHash());
106+
queuedTx.pop_front();
107+
}
108+
return first_tx;
109+
}
110+
111+
size_t size() const { return queuedTx.size(); }
112+
113+
void clear()
114+
{
115+
cachedInnerUsage = 0;
116+
iters_by_txid.clear();
117+
queuedTx.clear();
118+
}
119+
120+
/** Clear all data structures and return the list of transactions. */
121+
std::list<CTransactionRef> take()
122+
{
123+
std::list<CTransactionRef> ret = std::move(queuedTx);
124+
clear();
125+
return ret;
126+
}
127+
};
128+
#endif // BITCOIN_KERNEL_DISCONNECTED_TRANSACTIONS_H

src/test/validation_chainstatemanager_tests.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//
55
#include <chainparams.h>
66
#include <consensus/validation.h>
7+
#include <kernel/disconnected_transactions.h>
78
#include <node/kernel_notifications.h>
89
#include <node/utxo_snapshot.h>
910
#include <random.h>

src/txmempool.h

Lines changed: 0 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -836,118 +836,4 @@ class CCoinsViewMemPool : public CCoinsViewBacked
836836
* m_temp_added and cannot be flushed to the back end. Only used for package validation. */
837837
void PackageAddTransaction(const CTransactionRef& tx);
838838
};
839-
840-
/**
841-
* DisconnectedBlockTransactions
842-
843-
* During the reorg, it's desirable to re-add previously confirmed transactions
844-
* to the mempool, so that anything not re-confirmed in the new chain is
845-
* available to be mined. However, it's more efficient to wait until the reorg
846-
* is complete and process all still-unconfirmed transactions at that time,
847-
* since we expect most confirmed transactions to (typically) still be
848-
* confirmed in the new chain, and re-accepting to the memory pool is expensive
849-
* (and therefore better to not do in the middle of reorg-processing).
850-
* Instead, store the disconnected transactions (in order!) as we go, remove any
851-
* that are included in blocks in the new chain, and then process the remaining
852-
* still-unconfirmed transactions at the end.
853-
*
854-
* Order of queuedTx:
855-
* The front of the list should be the most recently-confirmed transactions (transactions at the
856-
* end of vtx of blocks closer to the tip). If memory usage grows too large, we trim from the front
857-
* of the list. After trimming, transactions can be re-added to the mempool from the back of the
858-
* list to the front without running into missing inputs.
859-
*/
860-
class DisconnectedBlockTransactions {
861-
private:
862-
/** Cached dynamic memory usage for the CTransactions (memory for the shared pointers is
863-
* included in the container calculations). */
864-
uint64_t cachedInnerUsage = 0;
865-
std::list<CTransactionRef> queuedTx;
866-
using TxList = decltype(queuedTx);
867-
std::unordered_map<uint256, TxList::iterator, SaltedTxidHasher> iters_by_txid;
868-
869-
public:
870-
// It's almost certainly a logic bug if we don't clear out queuedTx before
871-
// destruction, as we add to it while disconnecting blocks, and then we
872-
// need to re-process remaining transactions to ensure mempool consistency.
873-
// For now, assert() that we've emptied out this object on destruction.
874-
// This assert() can always be removed if the reorg-processing code were
875-
// to be refactored such that this assumption is no longer true (for
876-
// instance if there was some other way we cleaned up the mempool after a
877-
// reorg, besides draining this object).
878-
~DisconnectedBlockTransactions() {
879-
assert(queuedTx.empty());
880-
assert(iters_by_txid.empty());
881-
assert(cachedInnerUsage == 0);
882-
}
883-
884-
size_t DynamicMemoryUsage() const {
885-
return cachedInnerUsage + memusage::DynamicUsage(iters_by_txid) + memusage::DynamicUsage(queuedTx);
886-
}
887-
888-
/** Add transactions from the block, iterating through vtx in reverse order. Callers should call
889-
* this function for blocks in descending order by block height.
890-
* We assume that callers never pass multiple transactions with the same txid, otherwise things
891-
* can go very wrong in removeForBlock due to queuedTx containing an item without a
892-
* corresponding entry in iters_by_txid.
893-
*/
894-
void AddTransactionsFromBlock(const std::vector<CTransactionRef>& vtx)
895-
{
896-
iters_by_txid.reserve(iters_by_txid.size() + vtx.size());
897-
for (auto block_it = vtx.rbegin(); block_it != vtx.rend(); ++block_it) {
898-
auto it = queuedTx.insert(queuedTx.end(), *block_it);
899-
iters_by_txid.emplace((*block_it)->GetHash(), it);
900-
cachedInnerUsage += RecursiveDynamicUsage(**block_it);
901-
}
902-
}
903-
904-
/** Remove any entries that are in this block. */
905-
void removeForBlock(const std::vector<CTransactionRef>& vtx)
906-
{
907-
// Short-circuit in the common case of a block being added to the tip
908-
if (queuedTx.empty()) {
909-
return;
910-
}
911-
for (const auto& tx : vtx) {
912-
auto iter = iters_by_txid.find(tx->GetHash());
913-
if (iter != iters_by_txid.end()) {
914-
auto list_iter = iter->second;
915-
iters_by_txid.erase(iter);
916-
cachedInnerUsage -= RecursiveDynamicUsage(**list_iter);
917-
queuedTx.erase(list_iter);
918-
}
919-
}
920-
}
921-
922-
/** Remove the first entry and update memory usage. */
923-
CTransactionRef take_first()
924-
{
925-
CTransactionRef first_tx;
926-
if (!queuedTx.empty()) {
927-
first_tx = queuedTx.front();
928-
cachedInnerUsage -= RecursiveDynamicUsage(*queuedTx.front());
929-
iters_by_txid.erase(queuedTx.front()->GetHash());
930-
queuedTx.pop_front();
931-
}
932-
return first_tx;
933-
}
934-
935-
size_t size() const { return queuedTx.size(); }
936-
937-
void clear()
938-
{
939-
cachedInnerUsage = 0;
940-
iters_by_txid.clear();
941-
queuedTx.clear();
942-
}
943-
944-
/** Clear all data structures and return the list of transactions. */
945-
std::list<CTransactionRef> take()
946-
{
947-
std::list<CTransactionRef> ret = std::move(queuedTx);
948-
clear();
949-
return ret;
950-
}
951-
};
952-
953839
#endif // BITCOIN_TXMEMPOOL_H

src/validation.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <flatfile.h>
2222
#include <hash.h>
2323
#include <kernel/chainparams.h>
24+
#include <kernel/disconnected_transactions.h>
2425
#include <kernel/mempool_entry.h>
2526
#include <kernel/notifications_interface.h>
2627
#include <logging.h>

0 commit comments

Comments
 (0)