@@ -850,29 +850,23 @@ class CCoinsViewMemPool : public CCoinsViewBacked
850
850
* Instead, store the disconnected transactions (in order!) as we go, remove any
851
851
* that are included in blocks in the new chain, and then process the remaining
852
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.
853
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;
854
868
855
- // multi_index tag names
856
- struct txid_index {};
857
- struct insertion_order {};
858
-
859
- struct DisconnectedBlockTransactions {
860
- typedef boost::multi_index_container<
861
- CTransactionRef,
862
- boost::multi_index::indexed_by<
863
- // sorted by txid
864
- boost::multi_index::hashed_unique<
865
- boost::multi_index::tag<txid_index>,
866
- mempoolentry_txid,
867
- SaltedTxidHasher
868
- >,
869
- // sorted by order in the blockchain
870
- boost::multi_index::sequenced<
871
- boost::multi_index::tag<insertion_order>
872
- >
873
- >
874
- > indexed_disconnected_transactions;
875
-
869
+ public:
876
870
// It's almost certainly a logic bug if we don't clear out queuedTx before
877
871
// destruction, as we add to it while disconnecting blocks, and then we
878
872
// need to re-process remaining transactions to ensure mempool consistency.
@@ -881,59 +875,79 @@ struct DisconnectedBlockTransactions {
881
875
// to be refactored such that this assumption is no longer true (for
882
876
// instance if there was some other way we cleaned up the mempool after a
883
877
// reorg, besides draining this object).
884
- ~DisconnectedBlockTransactions () { assert (queuedTx.empty ()); }
885
-
886
- indexed_disconnected_transactions queuedTx;
887
- uint64_t cachedInnerUsage = 0 ;
878
+ ~DisconnectedBlockTransactions () {
879
+ assert (queuedTx.empty ());
880
+ assert (iters_by_txid.empty ());
881
+ assert (cachedInnerUsage == 0 );
882
+ }
888
883
889
- // Estimate the overhead of queuedTx to be 6 pointers + an allocation, as
890
- // no exact formula for boost::multi_index_contained is implemented.
891
884
size_t DynamicMemoryUsage () const {
892
- return memusage::MallocUsage ( sizeof (CTransactionRef ) + 6 * sizeof ( void *)) * queuedTx. size () + cachedInnerUsage ;
885
+ return cachedInnerUsage + memusage::DynamicUsage (iters_by_txid ) + memusage::DynamicUsage ( queuedTx) ;
893
886
}
894
887
895
- /* * Add transactions from the block, iterating through vtx in reverse order. Callers should call
888
+ /* * Add transactions from the block, iterating through vtx in reverse order. Callers should call
896
889
* this function for blocks in descending order by block height.
897
890
* We assume that callers never pass multiple transactions with the same txid, otherwise things
898
891
* can go very wrong in removeForBlock due to queuedTx containing an item without a
899
892
* corresponding entry in iters_by_txid.
900
893
*/
901
894
void AddTransactionsFromBlock (const std::vector<CTransactionRef>& vtx)
902
895
{
896
+ iters_by_txid.reserve (iters_by_txid.size () + vtx.size ());
903
897
for (auto block_it = vtx.rbegin (); block_it != vtx.rend (); ++block_it) {
904
- queuedTx.insert (*block_it);
905
- cachedInnerUsage += RecursiveDynamicUsage (*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);
906
901
}
907
902
}
908
903
909
- // Remove entries based on txid_index, and update memory usage.
904
+ /* * Remove any entries that are in this block. */
910
905
void removeForBlock (const std::vector<CTransactionRef>& vtx)
911
906
{
912
907
// Short-circuit in the common case of a block being added to the tip
913
908
if (queuedTx.empty ()) {
914
909
return ;
915
910
}
916
- for (auto const &tx : vtx) {
917
- auto it = queuedTx.find (tx->GetHash ());
918
- if (it != queuedTx.end ()) {
919
- cachedInnerUsage -= RecursiveDynamicUsage (*it);
920
- queuedTx.erase (it);
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);
921
918
}
922
919
}
923
920
}
924
921
925
- // Remove an entry by insertion_order index, and update memory usage.
926
- void removeEntry (indexed_disconnected_transactions::index<insertion_order>::type::iterator entry )
922
+ /* * Remove the first entry and update memory usage. */
923
+ CTransactionRef take_first ( )
927
924
{
928
- cachedInnerUsage -= RecursiveDynamicUsage (*entry);
929
- queuedTx.get <insertion_order>().erase (entry);
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;
930
933
}
931
934
935
+ size_t size () const { return queuedTx.size (); }
936
+
932
937
void clear ()
933
938
{
934
939
cachedInnerUsage = 0 ;
940
+ iters_by_txid.clear ();
935
941
queuedTx.clear ();
936
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
+ }
937
951
};
938
952
939
953
#endif // BITCOIN_TXMEMPOOL_H
0 commit comments