Skip to content

Commit 0673c95

Browse files
committed
tx_memory_pool: speedup get_complement() for large requests
Changes complexity from M*N to (2*N+M)*log2(M). The FCMP++ stressnet recently hit mempool sizes of ~55k txs. If the requesting node's mempool is populated, this results in an average of (55000*55000)/2 (about 1.5 billion) comparisons for the responding node. Under this commit, this would be reduced to (55000+55000)*log2(55000) comparisons (about 2.6 million), a 99.83% reduction.
1 parent 6bb3630 commit 0673c95

File tree

6 files changed

+18
-8
lines changed

6 files changed

+18
-8
lines changed

src/crypto/hash.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ namespace crypto {
101101

102102
constexpr static crypto::hash null_hash = {};
103103
constexpr static crypto::hash8 null_hash8 = {};
104+
105+
inline bool operator<(const hash &lhs, const hash &rhs) noexcept { return memcmp(&lhs, &rhs, sizeof(hash)) < 0; }
106+
inline bool operator>(const hash &lhs, const hash &rhs) noexcept { return rhs < lhs; }
104107
}
105108

106109
CRYPTO_MAKE_HASHABLE(hash)

src/cryptonote_core/cryptonote_core.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1850,9 +1850,9 @@ namespace cryptonote
18501850
m_blockchain_storage.flush_invalid_blocks();
18511851
}
18521852
//-----------------------------------------------------------------------------------------------
1853-
bool core::get_txpool_complement(const std::vector<crypto::hash> &hashes, std::vector<cryptonote::blobdata> &txes)
1853+
bool core::get_txpool_complement(std::vector<crypto::hash> hashes, std::vector<cryptonote::blobdata> &txes)
18541854
{
1855-
return m_mempool.get_complement(hashes, txes);
1855+
return m_mempool.get_complement(std::move(hashes), txes);
18561856
}
18571857
//-----------------------------------------------------------------------------------------------
18581858
bool core::update_blockchain_pruning()

src/cryptonote_core/cryptonote_core.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -897,7 +897,7 @@ namespace cryptonote
897897
*
898898
* @return true iff success, false otherwise
899899
*/
900-
bool get_txpool_complement(const std::vector<crypto::hash> &hashes, std::vector<cryptonote::blobdata> &txes);
900+
bool get_txpool_complement(std::vector<crypto::hash> hashes, std::vector<cryptonote::blobdata> &txes);
901901

902902
/**
903903
* @brief validates some simple properties of a transaction

src/cryptonote_core/tx_pool.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -666,17 +666,24 @@ namespace cryptonote
666666
return true;
667667
}
668668
//---------------------------------------------------------------------------------
669-
bool tx_memory_pool::get_complement(const std::vector<crypto::hash> &hashes, std::vector<cryptonote::blobdata> &txes) const
669+
bool tx_memory_pool::get_complement(std::vector<crypto::hash> hashes, std::vector<cryptonote::blobdata> &txes) const
670670
{
671671
CRITICAL_REGION_LOCAL(m_transactions_lock);
672672
CRITICAL_REGION_LOCAL1(m_blockchain);
673673

674+
// Sort so we can do binary search later
675+
std::sort(hashes.begin(), hashes.end());
676+
674677
m_blockchain.for_all_txpool_txes([this, &hashes, &txes](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata_ref*) {
675678
const auto tx_relay_method = meta.get_relay_method();
676679
if (tx_relay_method != relay_method::block && tx_relay_method != relay_method::fluff)
677680
return true;
678-
const auto i = std::find(hashes.begin(), hashes.end(), txid);
679-
if (i == hashes.end())
681+
682+
// Do binary search for our pool TXID in given list, skip to next if already present
683+
const auto hash_it = std::lower_bound(hashes.cbegin(), hashes.cend(), txid);
684+
if (hash_it != hashes.cend() && *hash_it == txid)
685+
return true;
686+
680687
{
681688
cryptonote::blobdata bd;
682689
try

src/cryptonote_core/tx_pool.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ namespace cryptonote
493493
/**
494494
* @brief get transactions not in the passed set
495495
*/
496-
bool get_complement(const std::vector<crypto::hash> &hashes, std::vector<cryptonote::blobdata> &txes) const;
496+
bool get_complement(std::vector<crypto::hash> hashes, std::vector<cryptonote::blobdata> &txes) const;
497497

498498
/**
499499
* @brief get info necessary for update of pool-related info in a wallet, preferably incremental

src/cryptonote_protocol/cryptonote_protocol_handler.inl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -863,7 +863,7 @@ namespace cryptonote
863863
std::vector<cryptonote::blobdata> local_txs;
864864

865865
std::vector<cryptonote::blobdata> txes;
866-
if (!m_core.get_txpool_complement(arg.hashes, txes))
866+
if (!m_core.get_txpool_complement(std::move(arg.hashes), txes))
867867
{
868868
LOG_ERROR_CCONTEXT("failed to get txpool complement");
869869
return 1;

0 commit comments

Comments
 (0)