diff options
Diffstat (limited to 'src/blockchain_db')
-rw-r--r-- | src/blockchain_db/blockchain_db.cpp | 84 | ||||
-rw-r--r-- | src/blockchain_db/blockchain_db.h | 49 | ||||
-rw-r--r-- | src/blockchain_db/lmdb/db_lmdb.cpp | 58 | ||||
-rw-r--r-- | src/blockchain_db/lmdb/db_lmdb.h | 10 | ||||
-rw-r--r-- | src/blockchain_db/testdb.h | 10 |
5 files changed, 180 insertions, 31 deletions
diff --git a/src/blockchain_db/blockchain_db.cpp b/src/blockchain_db/blockchain_db.cpp index 63ac38a88..1a6a19da5 100644 --- a/src/blockchain_db/blockchain_db.cpp +++ b/src/blockchain_db/blockchain_db.cpp @@ -44,6 +44,71 @@ using epee::string_tools::pod_to_hex; namespace cryptonote { +bool matches_category(relay_method method, relay_category category) noexcept +{ + switch (category) + { + default: + return false; + case relay_category::all: + return true; + case relay_category::relayable: + if (method == relay_method::none) + return false; + return true; + case relay_category::broadcasted: + case relay_category::legacy: + break; + } + // check for "broadcasted" or "legacy" methods: + switch (method) + { + default: + case relay_method::local: + return false; + case relay_method::block: + case relay_method::fluff: + return true; + case relay_method::none: + break; + } + return category == relay_category::legacy; +} + +void txpool_tx_meta_t::set_relay_method(relay_method method) noexcept +{ + kept_by_block = 0; + do_not_relay = 0; + is_local = 0; + + switch (method) + { + case relay_method::none: + do_not_relay = 1; + break; + case relay_method::local: + is_local = 1; + break; + default: + case relay_method::fluff: + break; + case relay_method::block: + kept_by_block = 1; + break; + } +} + +relay_method txpool_tx_meta_t::get_relay_method() const noexcept +{ + if (kept_by_block) + return relay_method::block; + if (do_not_relay) + return relay_method::none; + if (is_local) + return relay_method::local; + return relay_method::fluff; +} + const command_line::arg_descriptor<std::string> arg_db_sync_mode = { "db-sync-mode" , "Specify sync option, using format [safe|fast|fastest]:[sync|async]:[<nblocks_per_sync>[blocks]|<nbytes_per_sync>[bytes]]." @@ -924,4 +989,23 @@ void BlockchainDB::fixup() batch_stop(); } +bool BlockchainDB::txpool_tx_matches_category(const crypto::hash& tx_hash, relay_category category) +{ + try + { + txpool_tx_meta_t meta{}; + if (!get_txpool_tx_meta(tx_hash, meta)) + { + MERROR("Failed to get tx meta from txpool"); + return false; + } + return meta.matches(category); + } + catch (const std::exception &e) + { + MERROR("Failed to get tx meta from txpool: " << e.what()); + } + return false; +} + } // namespace cryptonote diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index 21700d5d3..e9fc85803 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -39,6 +39,7 @@ #include "cryptonote_basic/cryptonote_basic.h" #include "cryptonote_basic/difficulty.h" #include "cryptonote_basic/hardfork.h" +#include "cryptonote_protocol/enums.h" /** \file * Cryptonote Blockchain Database Interface @@ -105,6 +106,16 @@ typedef std::pair<crypto::hash, uint64_t> tx_out_index; extern const command_line::arg_descriptor<std::string> arg_db_sync_mode; extern const command_line::arg_descriptor<bool, false> arg_db_salvage; +enum class relay_category : uint8_t +{ + broadcasted = 0,//!< Public txes received via block/fluff + relayable, //!< Every tx not marked `relay_method::none` + legacy, //!< `relay_category::broadcasted` + `relay_method::none` for rpc relay requests or historical reasons + all //!< Everything in the db +}; + +bool matches_category(relay_method method, relay_category category) noexcept; + #pragma pack(push, 1) /** @@ -156,11 +167,22 @@ struct txpool_tx_meta_t uint8_t do_not_relay; uint8_t double_spend_seen: 1; uint8_t pruned: 1; - uint8_t bf_padding: 6; + uint8_t is_local: 1; + uint8_t bf_padding: 5; uint8_t padding[76]; // till 192 bytes + + void set_relay_method(relay_method method) noexcept; + relay_method get_relay_method() const noexcept; + + //! See `relay_category` description + bool matches(const relay_category category) const noexcept + { + return matches_category(get_relay_method(), category); + } }; + #define DBF_SAFE 1 #define DBF_FAST 2 #define DBF_FASTEST 4 @@ -1481,12 +1503,12 @@ public: /** * @brief get the number of transactions in the txpool */ - virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const = 0; + virtual uint64_t get_txpool_tx_count(relay_category tx_category = relay_category::broadcasted) const = 0; /** - * @brief check whether a txid is in the txpool + * @brief check whether a txid is in the txpool and meets tx_category requirements */ - virtual bool txpool_has_tx(const crypto::hash &txid) const = 0; + virtual bool txpool_has_tx(const crypto::hash &txid, relay_category tx_category) const = 0; /** * @brief remove a txpool transaction @@ -1510,10 +1532,11 @@ public: * * @param txid the transaction id of the transation to lookup * @param bd the blob to return + * @param tx_category for filtering out hidden/private txes * - * @return true if the txid was in the txpool, false otherwise + * @return True iff `txid` is in the pool and meets `tx_category` requirements */ - virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const = 0; + virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd, relay_category tx_category) const = 0; /** * @brief get a txpool transaction's blob @@ -1522,7 +1545,17 @@ public: * * @return the blob for that transaction */ - virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const = 0; + virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid, relay_category tx_category) const = 0; + + /** + * @brief Check if `tx_hash` relay status is in `category`. + * + * @param tx_hash hash of the transaction to lookup + * @param category relay status category to test against + * + * @return True if `tx_hash` latest relay status is in `category`. + */ + bool txpool_tx_matches_category(const crypto::hash& tx_hash, relay_category category); /** * @brief prune output data for the given amount @@ -1620,7 +1653,7 @@ public: * * @return false if the function returns false for any transaction, otherwise true */ - virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false, bool include_unrelayed_txes = true) const = 0; + virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false, relay_category category = relay_category::broadcasted) const = 0; /** * @brief runs a function over all key images stored diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 495d70e7d..5093015f2 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -163,7 +163,15 @@ int BlockchainLMDB::compare_string(const MDB_val *a, const MDB_val *b) { const char *va = (const char*) a->mv_data; const char *vb = (const char*) b->mv_data; - return strcmp(va, vb); + const size_t sz = std::min(a->mv_size, b->mv_size); + int ret = strncmp(va, vb, sz); + if (ret) + return ret; + if (a->mv_size < b->mv_size) + return -1; + if (a->mv_size > b->mv_size) + return 1; + return 0; } } @@ -1771,7 +1779,7 @@ void BlockchainLMDB::update_txpool_tx(const crypto::hash &txid, const txpool_tx_ } } -uint64_t BlockchainLMDB::get_txpool_tx_count(bool include_unrelayed_txes) const +uint64_t BlockchainLMDB::get_txpool_tx_count(relay_category category) const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); check_open(); @@ -1781,7 +1789,7 @@ uint64_t BlockchainLMDB::get_txpool_tx_count(bool include_unrelayed_txes) const TXN_PREFIX_RDONLY(); - if (include_unrelayed_txes) + if (category == relay_category::all) { // No filtering, we can get the number of tx the "fast" way MDB_stat db_stats; @@ -1807,7 +1815,7 @@ uint64_t BlockchainLMDB::get_txpool_tx_count(bool include_unrelayed_txes) const if (result) throw0(DB_ERROR(lmdb_error("Failed to enumerate txpool tx metadata: ", result).c_str())); const txpool_tx_meta_t &meta = *(const txpool_tx_meta_t*)v.mv_data; - if (!meta.do_not_relay) + if (meta.matches(category)) ++num_entries; } } @@ -1816,7 +1824,7 @@ uint64_t BlockchainLMDB::get_txpool_tx_count(bool include_unrelayed_txes) const return num_entries; } -bool BlockchainLMDB::txpool_has_tx(const crypto::hash& txid) const +bool BlockchainLMDB::txpool_has_tx(const crypto::hash& txid, relay_category tx_category) const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); check_open(); @@ -1825,11 +1833,21 @@ bool BlockchainLMDB::txpool_has_tx(const crypto::hash& txid) const RCURSOR(txpool_meta) MDB_val k = {sizeof(txid), (void *)&txid}; - auto result = mdb_cursor_get(m_cur_txpool_meta, &k, NULL, MDB_SET); + MDB_val v; + auto result = mdb_cursor_get(m_cur_txpool_meta, &k, &v, MDB_SET); if (result != 0 && result != MDB_NOTFOUND) throw1(DB_ERROR(lmdb_error("Error finding txpool tx meta: ", result).c_str())); + if (result == MDB_NOTFOUND) + return false; + + bool found = true; + if (tx_category != relay_category::all) + { + const txpool_tx_meta_t &meta = *(const txpool_tx_meta_t*)v.mv_data; + found = meta.matches(tx_category); + } TXN_POSTFIX_RDONLY(); - return result != MDB_NOTFOUND; + return found; } void BlockchainLMDB::remove_txpool_tx(const crypto::hash& txid) @@ -1883,7 +1901,7 @@ bool BlockchainLMDB::get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta return true; } -bool BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const +bool BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd, relay_category tx_category) const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); check_open(); @@ -1893,6 +1911,21 @@ bool BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid, cryptonote::bl MDB_val k = {sizeof(txid), (void *)&txid}; MDB_val v; + + // if filtering, make sure those requirements are met before copying blob + if (tx_category != relay_category::all) + { + auto result = mdb_cursor_get(m_cur_txpool_meta, &k, &v, MDB_SET); + if (result == MDB_NOTFOUND) + return false; + if (result != 0) + throw1(DB_ERROR(lmdb_error("Error finding txpool tx meta: ", result).c_str())); + + const txpool_tx_meta_t& meta = *(const txpool_tx_meta_t*)v.mv_data; + if (!meta.matches(tx_category)) + return false; + } + auto result = mdb_cursor_get(m_cur_txpool_blob, &k, &v, MDB_SET); if (result == MDB_NOTFOUND) return false; @@ -1904,10 +1937,10 @@ bool BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid, cryptonote::bl return true; } -cryptonote::blobdata BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid) const +cryptonote::blobdata BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid, relay_category tx_category) const { cryptonote::blobdata bd; - if (!get_txpool_tx_blob(txid, bd)) + if (!get_txpool_tx_blob(txid, bd, tx_category)) throw1(DB_ERROR("Tx not found in txpool: ")); return bd; } @@ -2245,7 +2278,7 @@ bool BlockchainLMDB::check_pruning() return prune_worker(prune_mode_check, 0); } -bool BlockchainLMDB::for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob, bool include_unrelayed_txes) const +bool BlockchainLMDB::for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob, relay_category category) const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); check_open(); @@ -2269,8 +2302,7 @@ bool BlockchainLMDB::for_all_txpool_txes(std::function<bool(const crypto::hash&, throw0(DB_ERROR(lmdb_error("Failed to enumerate txpool tx metadata: ", result).c_str())); const crypto::hash txid = *(const crypto::hash*)k.mv_data; const txpool_tx_meta_t &meta = *(const txpool_tx_meta_t*)v.mv_data; - if (!include_unrelayed_txes && meta.do_not_relay) - // Skipping that tx + if (!meta.matches(category)) continue; const cryptonote::blobdata *passed_bd = NULL; cryptonote::blobdata bd; diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h index 5dd44ec67..7c0b4c72c 100644 --- a/src/blockchain_db/lmdb/db_lmdb.h +++ b/src/blockchain_db/lmdb/db_lmdb.h @@ -282,12 +282,12 @@ public: virtual void add_txpool_tx(const crypto::hash &txid, const cryptonote::blobdata &blob, const txpool_tx_meta_t& meta); virtual void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t& meta); - virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const; - virtual bool txpool_has_tx(const crypto::hash &txid) const; + virtual uint64_t get_txpool_tx_count(relay_category category = relay_category::broadcasted) const; + virtual bool txpool_has_tx(const crypto::hash &txid, relay_category tx_category) const; virtual void remove_txpool_tx(const crypto::hash& txid); virtual bool get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const; - virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const; - virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const; + virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata& bd, relay_category tx_category) const; + virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid, relay_category tx_category) const; virtual uint32_t get_blockchain_pruning_seed() const; virtual bool prune_blockchain(uint32_t pruning_seed = 0); virtual bool update_pruning(); @@ -299,7 +299,7 @@ public: virtual uint64_t get_alt_block_count(); virtual void drop_alt_blocks(); - virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob = false, bool include_unrelayed_txes = true) const; + virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob = false, relay_category category = relay_category::broadcasted) const; virtual bool for_all_key_images(std::function<bool(const crypto::key_image&)>) const; virtual bool for_blocks_range(const uint64_t& h1, const uint64_t& h2, std::function<bool(uint64_t, const crypto::hash&, const cryptonote::block&)>) const; diff --git a/src/blockchain_db/testdb.h b/src/blockchain_db/testdb.h index 4176e087c..46de38c7e 100644 --- a/src/blockchain_db/testdb.h +++ b/src/blockchain_db/testdb.h @@ -127,14 +127,14 @@ public: virtual void add_txpool_tx(const crypto::hash &txid, const cryptonote::blobdata &blob, const cryptonote::txpool_tx_meta_t& details) override {} virtual void update_txpool_tx(const crypto::hash &txid, const cryptonote::txpool_tx_meta_t& details) override {} - virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const override { return 0; } - virtual bool txpool_has_tx(const crypto::hash &txid) const override { return false; } + virtual uint64_t get_txpool_tx_count(relay_category tx_relay = relay_category::broadcasted) const override { return 0; } + virtual bool txpool_has_tx(const crypto::hash &txid, relay_category tx_category) const override { return false; } virtual void remove_txpool_tx(const crypto::hash& txid) override {} virtual bool get_txpool_tx_meta(const crypto::hash& txid, cryptonote::txpool_tx_meta_t &meta) const override { return false; } - virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const override { return false; } + virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd, relay_category tx_category) const override { return false; } virtual uint64_t get_database_size() const override { return 0; } - virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const override { return ""; } - virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const cryptonote::txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false, bool include_unrelayed_txes = false) const override { return false; } + virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid, relay_category tx_category) const override { return ""; } + virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const cryptonote::txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false, relay_category category = relay_category::broadcasted) const override { return false; } virtual void add_block( const cryptonote::block& blk , size_t block_weight |