aboutsummaryrefslogtreecommitdiff
path: root/src/blockchain_db
diff options
context:
space:
mode:
Diffstat (limited to 'src/blockchain_db')
-rw-r--r--src/blockchain_db/blockchain_db.h15
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp52
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h2
-rw-r--r--src/blockchain_db/testdb.h1
4 files changed, 70 insertions, 0 deletions
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index b38ec9e05..9628a5c4d 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -1306,6 +1306,21 @@ public:
virtual bool get_pruned_tx_blobs_from(const crypto::hash& h, size_t count, std::vector<cryptonote::blobdata> &bd) const = 0;
/**
+ * @brief Get all txids in the database (chain and pool) that match a certain nbits txid template
+ *
+ * To be more specific, for all `dbtxid` txids in the database, return `dbtxid` if
+ * `0 == cryptonote::compare_hash32_reversed_nbits(txid_template, dbtxid, nbits)`.
+ *
+ * @param txid_template the transaction id template
+ * @param nbits number of bits to compare against in the template
+ * @param max_num_txs The maximum number of txids to match, if we hit this limit, throw early
+ * @return std::vector<crypto::hash> the list of all matching txids
+ *
+ * @throw TX_EXISTS if the number of txids that match exceed `max_num_txs`
+ */
+ virtual std::vector<crypto::hash> get_txids_loose(const crypto::hash& txid_template, std::uint32_t nbits, uint64_t max_num_txs = 0) = 0;
+
+ /**
* @brief fetches a variable number of blocks and transactions from the given height, in canonical blockchain order
*
* The subclass should return the blocks and transactions stored from the one with the given
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index 4178c862b..2c015faee 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -3144,6 +3144,58 @@ bool BlockchainLMDB::get_pruned_tx_blobs_from(const crypto::hash& h, size_t coun
return true;
}
+std::vector<crypto::hash> BlockchainLMDB::get_txids_loose(const crypto::hash& txid_template, std::uint32_t bits, uint64_t max_num_txs)
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+
+ std::vector<crypto::hash> matching_hashes;
+
+ TXN_PREFIX_RDONLY(); // Start a read-only transaction
+ RCURSOR(tx_indices); // Open cursors to the tx_indices and txpool_meta databases
+ RCURSOR(txpool_meta);
+
+ // Search on-chain and pool transactions together, starting with on-chain txs
+ MDB_cursor* cursor = m_cur_tx_indices;
+ MDB_val k = zerokval; // tx_indicies DB uses a dummy key
+ MDB_val_set(v, txid_template); // tx_indicies DB indexes data values by crypto::hash value on front
+ MDB_cursor_op op = MDB_GET_BOTH_RANGE; // Set the cursor to the first key/value pair >= the given key
+ bool doing_chain = true; // this variable tells us whether we are processing chain or pool txs
+ while (1)
+ {
+ const int get_result = mdb_cursor_get(cursor, &k, &v, op);
+ op = doing_chain ? MDB_NEXT_DUP : MDB_NEXT; // Set the cursor to the next key/value pair
+ if (get_result && get_result != MDB_NOTFOUND)
+ throw0(DB_ERROR(lmdb_error("DB error attempting to fetch txid range", get_result).c_str()));
+
+ // In tx_indicies, the hash is stored at the data, in txpool_meta at the key
+ const crypto::hash* const p_dbtxid = (const crypto::hash*)(doing_chain ? v.mv_data : k.mv_data);
+
+ // Check if we reached the end of a DB or the hashes no longer match the template
+ if (get_result == MDB_NOTFOUND || compare_hash32_reversed_nbits(txid_template, *p_dbtxid, bits))
+ {
+ if (doing_chain) // done with chain processing, switch to pool processing
+ {
+ k.mv_size = sizeof(crypto::hash); // txpool_meta DB is indexed using crypto::hash as keys
+ k.mv_data = (void*) txid_template.data;
+ cursor = m_cur_txpool_meta; // switch databases
+ op = MDB_SET_RANGE; // Set the cursor to the first key >= the given key
+ doing_chain = false;
+ continue;
+ }
+ break; // if we get to this point, then we finished pool processing and we are done
+ }
+ else if (matching_hashes.size() >= max_num_txs && max_num_txs != 0)
+ throw0(TX_EXISTS("number of tx hashes in template range exceeds maximum"));
+
+ matching_hashes.push_back(*p_dbtxid);
+ }
+
+ TXN_POSTFIX_RDONLY(); // End the read-only transaction
+
+ return matching_hashes;
+}
+
bool BlockchainLMDB::get_blocks_from(uint64_t start_height, size_t min_block_count, size_t max_block_count, size_t max_tx_count, size_t max_size, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata>>>>& blocks, bool pruned, bool skip_coinbase, bool get_miner_tx_hash) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index c352458b4..95e7b2aa4 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -262,6 +262,8 @@ public:
virtual bool get_prunable_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const;
virtual bool get_prunable_tx_hash(const crypto::hash& tx_hash, crypto::hash &prunable_hash) const;
+ virtual std::vector<crypto::hash> get_txids_loose(const crypto::hash& h, std::uint32_t bits, uint64_t max_num_txs = 0);
+
virtual uint64_t get_tx_count() const;
virtual std::vector<transaction> get_tx_list(const std::vector<crypto::hash>& hlist) const;
diff --git a/src/blockchain_db/testdb.h b/src/blockchain_db/testdb.h
index 946f26270..a27183b2c 100644
--- a/src/blockchain_db/testdb.h
+++ b/src/blockchain_db/testdb.h
@@ -71,6 +71,7 @@ public:
virtual bool get_pruned_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const override { return false; }
virtual bool get_pruned_tx_blobs_from(const crypto::hash& h, size_t count, std::vector<cryptonote::blobdata> &bd) const override { return false; }
virtual bool get_blocks_from(uint64_t start_height, size_t min_block_count, size_t max_block_count, size_t max_tx_count, size_t max_size, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata>>>>& blocks, bool pruned, bool skip_coinbase, bool get_miner_tx_hash) const override { return false; }
+ virtual std::vector<crypto::hash> get_txids_loose(const crypto::hash& h, std::uint32_t bits, uint64_t max_num_txs = 0) override { return {}; }
virtual bool get_prunable_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const override { return false; }
virtual bool get_prunable_tx_hash(const crypto::hash& tx_hash, crypto::hash &prunable_hash) const override { return false; }
virtual uint64_t get_block_height(const crypto::hash& h) const override { return 0; }