Protect node privacy by proper filtering in restricted-mode RPC answers

This patch allows to filter out sensitive information for queries that rely on the pool state, when running in restricted mode.
This filtering is only applied to data sent back to RPC queries. Results of inline commands typed locally in the daemon are not affected.
In practice, when running with `--restricted-rpc`:
* get_transaction_pool will list relayed transactions with the fields "last relayed time" and "received time" set to zero.
* get_transaction_pool will not list transaction that have do_not_relay set to true, and will not list key images that are used only for such transactions
* get_transaction_pool_hashes.bin will not list such transaction
* get_transaction_pool_stats will not count such transactions in any of the aggregated values that are computed

The implementation does not make filtering the default, so developers should be mindful of this if they add new RPC functionality.
Fixes #2590.
This commit is contained in:
binaryFate 2017-11-08 13:06:41 +01:00
parent a2c2f4e4b0
commit 10013e9434
13 changed files with 140 additions and 75 deletions

View File

@ -1314,7 +1314,7 @@ public:
/** /**
* @brief get the number of transactions in the txpool * @brief get the number of transactions in the txpool
*/ */
virtual uint64_t get_txpool_tx_count() const = 0; virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const = 0;
/** /**
* @brief check whether a txid is in the txpool * @brief check whether a txid is in the txpool
@ -1369,7 +1369,7 @@ public:
* *
* @return false if the function returns false for any transaction, otherwise true * @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) 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, bool include_unrelayed_txes = true) const = 0;
/** /**
* @brief runs a function over all key images stored * @brief runs a function over all key images stored

View File

@ -1522,21 +1522,49 @@ void BlockchainLMDB::update_txpool_tx(const crypto::hash &txid, const txpool_tx_
} }
} }
uint64_t BlockchainLMDB::get_txpool_tx_count() const uint64_t BlockchainLMDB::get_txpool_tx_count(bool include_unrelayed_txes) const
{ {
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
TXN_PREFIX_RDONLY();
int result; int result;
uint64_t num_entries = 0;
MDB_stat db_stats; TXN_PREFIX_RDONLY();
if ((result = mdb_stat(m_txn, m_txpool_meta, &db_stats)))
throw0(DB_ERROR(lmdb_error("Failed to query m_txpool_meta: ", result).c_str()));
if (include_unrelayed_txes)
{
// No filtering, we can get the number of tx the "fast" way
MDB_stat db_stats;
if ((result = mdb_stat(m_txn, m_txpool_meta, &db_stats)))
throw0(DB_ERROR(lmdb_error("Failed to query m_txpool_meta: ", result).c_str()));
num_entries = db_stats.ms_entries;
}
else
{
// Filter unrelayed tx out of the result, so we need to loop over transactions and check their meta data
RCURSOR(txpool_meta);
RCURSOR(txpool_blob);
MDB_val k;
MDB_val v;
MDB_cursor_op op = MDB_FIRST;
while (1)
{
result = mdb_cursor_get(m_cur_txpool_meta, &k, &v, op);
op = MDB_NEXT;
if (result == MDB_NOTFOUND)
break;
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)
++num_entries;
}
}
TXN_POSTFIX_RDONLY(); TXN_POSTFIX_RDONLY();
return db_stats.ms_entries; return num_entries;
} }
bool BlockchainLMDB::txpool_has_tx(const crypto::hash& txid) const bool BlockchainLMDB::txpool_has_tx(const crypto::hash& txid) const
@ -1633,7 +1661,7 @@ cryptonote::blobdata BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid
return bd; return bd;
} }
bool BlockchainLMDB::for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob) 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, bool include_unrelayed_txes) const
{ {
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
@ -1657,6 +1685,9 @@ 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())); 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 crypto::hash txid = *(const crypto::hash*)k.mv_data;
const txpool_tx_meta_t &meta = *(const txpool_tx_meta_t*)v.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
continue;
const cryptonote::blobdata *passed_bd = NULL; const cryptonote::blobdata *passed_bd = NULL;
cryptonote::blobdata bd; cryptonote::blobdata bd;
if (include_blob) if (include_blob)

View File

@ -243,13 +243,13 @@ public:
virtual void add_txpool_tx(const transaction &tx, const txpool_tx_meta_t& meta); virtual void add_txpool_tx(const transaction &tx, const txpool_tx_meta_t& meta);
virtual void update_txpool_tx(const crypto::hash &txid, 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() const; virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const;
virtual bool txpool_has_tx(const crypto::hash &txid) const; virtual bool txpool_has_tx(const crypto::hash &txid) const;
virtual void remove_txpool_tx(const crypto::hash& txid); virtual void remove_txpool_tx(const crypto::hash& txid);
virtual txpool_tx_meta_t get_txpool_tx_meta(const crypto::hash& txid) const; virtual txpool_tx_meta_t get_txpool_tx_meta(const crypto::hash& txid) const;
virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) 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 cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) 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) 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, bool include_unrelayed_txes = true) const;
virtual bool for_all_key_images(std::function<bool(const crypto::key_image&)>) 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; 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;

View File

@ -4211,9 +4211,9 @@ void Blockchain::remove_txpool_tx(const crypto::hash &txid)
m_db->remove_txpool_tx(txid); m_db->remove_txpool_tx(txid);
} }
uint64_t Blockchain::get_txpool_tx_count() const uint64_t Blockchain::get_txpool_tx_count(bool include_unrelayed_txes) const
{ {
return m_db->get_txpool_tx_count(); return m_db->get_txpool_tx_count(include_unrelayed_txes);
} }
txpool_tx_meta_t Blockchain::get_txpool_tx_meta(const crypto::hash& txid) const txpool_tx_meta_t Blockchain::get_txpool_tx_meta(const crypto::hash& txid) const
@ -4231,9 +4231,9 @@ cryptonote::blobdata Blockchain::get_txpool_tx_blob(const crypto::hash& txid) co
return m_db->get_txpool_tx_blob(txid); return m_db->get_txpool_tx_blob(txid);
} }
bool Blockchain::for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob) const bool Blockchain::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
{ {
return m_db->for_all_txpool_txes(f, include_blob); return m_db->for_all_txpool_txes(f, include_blob, include_unrelayed_txes);
} }
void Blockchain::set_user_options(uint64_t maxthreads, uint64_t blocks_per_sync, blockchain_db_sync_mode sync_mode, bool fast_sync) void Blockchain::set_user_options(uint64_t maxthreads, uint64_t blocks_per_sync, blockchain_db_sync_mode sync_mode, bool fast_sync)

View File

@ -947,11 +947,11 @@ namespace cryptonote
void add_txpool_tx(transaction &tx, const txpool_tx_meta_t &meta); void add_txpool_tx(transaction &tx, const txpool_tx_meta_t &meta);
void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t &meta); void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t &meta);
void remove_txpool_tx(const crypto::hash &txid); void remove_txpool_tx(const crypto::hash &txid);
uint64_t get_txpool_tx_count() const; uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const;
txpool_tx_meta_t get_txpool_tx_meta(const crypto::hash& txid) const; txpool_tx_meta_t get_txpool_tx_meta(const crypto::hash& txid) const;
bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const; bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const;
cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const; cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const;
bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false) const; 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;
bool is_within_compiled_block_hash_area(uint64_t height) const; bool is_within_compiled_block_hash_area(uint64_t height) const;
bool is_within_compiled_block_hash_area() const { return is_within_compiled_block_hash_area(m_db->height()); } bool is_within_compiled_block_hash_area() const { return is_within_compiled_block_hash_area(m_db->height()); }

View File

@ -1182,21 +1182,21 @@ namespace cryptonote
return true; return true;
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::get_pool_transactions(std::list<transaction>& txs) const bool core::get_pool_transactions(std::list<transaction>& txs, bool include_sensitive_data) const
{ {
m_mempool.get_transactions(txs); m_mempool.get_transactions(txs, include_sensitive_data);
return true; return true;
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::get_pool_transaction_hashes(std::vector<crypto::hash>& txs) const bool core::get_pool_transaction_hashes(std::vector<crypto::hash>& txs, bool include_sensitive_data) const
{ {
m_mempool.get_transaction_hashes(txs); m_mempool.get_transaction_hashes(txs, include_sensitive_data);
return true; return true;
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::get_pool_transaction_stats(struct txpool_stats& stats) const bool core::get_pool_transaction_stats(struct txpool_stats& stats, bool include_sensitive_data) const
{ {
m_mempool.get_transaction_stats(stats); m_mempool.get_transaction_stats(stats, include_sensitive_data);
return true; return true;
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
@ -1210,9 +1210,9 @@ namespace cryptonote
return m_mempool.have_tx(id); return m_mempool.have_tx(id);
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::get_pool_transactions_and_spent_keys_info(std::vector<tx_info>& tx_infos, std::vector<spent_key_image_info>& key_image_infos) const bool core::get_pool_transactions_and_spent_keys_info(std::vector<tx_info>& tx_infos, std::vector<spent_key_image_info>& key_image_infos, bool include_sensitive_data) const
{ {
return m_mempool.get_transactions_and_spent_keys_info(tx_infos, key_image_infos); return m_mempool.get_transactions_and_spent_keys_info(tx_infos, key_image_infos, include_sensitive_data);
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::get_pool_for_rpc(std::vector<cryptonote::rpc::tx_in_pool>& tx_infos, cryptonote::rpc::key_images_with_tx_hashes& key_image_infos) const bool core::get_pool_for_rpc(std::vector<cryptonote::rpc::tx_in_pool>& tx_infos, cryptonote::rpc::key_images_with_tx_hashes& key_image_infos) const

View File

@ -420,11 +420,12 @@ namespace cryptonote
/** /**
* @copydoc tx_memory_pool::get_transactions * @copydoc tx_memory_pool::get_transactions
* @param include_unrelayed_txes include unrelayed txes in result
* *
* @note see tx_memory_pool::get_transactions * @note see tx_memory_pool::get_transactions
*/ */
bool get_pool_transactions(std::list<transaction>& txs) const; bool get_pool_transactions(std::list<transaction>& txs, bool include_unrelayed_txes = true) const;
/** /**
* @copydoc tx_memory_pool::get_txpool_backlog * @copydoc tx_memory_pool::get_txpool_backlog
* *
@ -434,17 +435,19 @@ namespace cryptonote
/** /**
* @copydoc tx_memory_pool::get_transactions * @copydoc tx_memory_pool::get_transactions
* @param include_unrelayed_txes include unrelayed txes in result
* *
* @note see tx_memory_pool::get_transactions * @note see tx_memory_pool::get_transactions
*/ */
bool get_pool_transaction_hashes(std::vector<crypto::hash>& txs) const; bool get_pool_transaction_hashes(std::vector<crypto::hash>& txs, bool include_unrelayed_txes = true) const;
/** /**
* @copydoc tx_memory_pool::get_transactions * @copydoc tx_memory_pool::get_transactions
* @param include_unrelayed_txes include unrelayed txes in result
* *
* @note see tx_memory_pool::get_transactions * @note see tx_memory_pool::get_transactions
*/ */
bool get_pool_transaction_stats(struct txpool_stats& stats) const; bool get_pool_transaction_stats(struct txpool_stats& stats, bool include_unrelayed_txes = true) const;
/** /**
* @copydoc tx_memory_pool::get_transaction * @copydoc tx_memory_pool::get_transaction
@ -455,10 +458,11 @@ namespace cryptonote
/** /**
* @copydoc tx_memory_pool::get_pool_transactions_and_spent_keys_info * @copydoc tx_memory_pool::get_pool_transactions_and_spent_keys_info
* @param include_unrelayed_txes include unrelayed txes in result
* *
* @note see tx_memory_pool::get_pool_transactions_and_spent_keys_info * @note see tx_memory_pool::get_pool_transactions_and_spent_keys_info
*/ */
bool get_pool_transactions_and_spent_keys_info(std::vector<tx_info>& tx_infos, std::vector<spent_key_image_info>& key_image_infos) const; bool get_pool_transactions_and_spent_keys_info(std::vector<tx_info>& tx_infos, std::vector<spent_key_image_info>& key_image_infos, bool include_unrelayed_txes = true) const;
/** /**
* @copydoc tx_memory_pool::get_pool_for_rpc * @copydoc tx_memory_pool::get_pool_for_rpc

View File

@ -432,7 +432,7 @@ namespace cryptonote
remove.insert(txid); remove.insert(txid);
} }
return true; return true;
}); }, false);
if (!remove.empty()) if (!remove.empty())
{ {
@ -494,7 +494,7 @@ namespace cryptonote
} }
} }
return true; return true;
}); }, false);
return true; return true;
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
@ -521,14 +521,14 @@ namespace cryptonote
} }
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
size_t tx_memory_pool::get_transactions_count() const size_t tx_memory_pool::get_transactions_count(bool include_unrelayed_txes) const
{ {
CRITICAL_REGION_LOCAL(m_transactions_lock); CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain); CRITICAL_REGION_LOCAL1(m_blockchain);
return m_blockchain.get_txpool_tx_count(); return m_blockchain.get_txpool_tx_count(include_unrelayed_txes);
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
void tx_memory_pool::get_transactions(std::list<transaction>& txs) const void tx_memory_pool::get_transactions(std::list<transaction>& txs, bool include_unrelayed_txes) const
{ {
CRITICAL_REGION_LOCAL(m_transactions_lock); CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain); CRITICAL_REGION_LOCAL1(m_blockchain);
@ -542,20 +542,20 @@ namespace cryptonote
} }
txs.push_back(tx); txs.push_back(tx);
return true; return true;
}, true); }, true, include_unrelayed_txes);
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
void tx_memory_pool::get_transaction_hashes(std::vector<crypto::hash>& txs) const void tx_memory_pool::get_transaction_hashes(std::vector<crypto::hash>& txs, bool include_unrelayed_txes) const
{ {
CRITICAL_REGION_LOCAL(m_transactions_lock); CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain); CRITICAL_REGION_LOCAL1(m_blockchain);
m_blockchain.for_all_txpool_txes([&txs](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){ m_blockchain.for_all_txpool_txes([&txs](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
txs.push_back(txid); txs.push_back(txid);
return true; return true;
}); }, false, include_unrelayed_txes);
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
void tx_memory_pool::get_transaction_backlog(std::vector<tx_backlog_entry>& backlog) const void tx_memory_pool::get_transaction_backlog(std::vector<tx_backlog_entry>& backlog, bool include_unrelayed_txes) const
{ {
CRITICAL_REGION_LOCAL(m_transactions_lock); CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain); CRITICAL_REGION_LOCAL1(m_blockchain);
@ -563,16 +563,16 @@ namespace cryptonote
m_blockchain.for_all_txpool_txes([&backlog, now](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){ m_blockchain.for_all_txpool_txes([&backlog, now](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
backlog.push_back({meta.blob_size, meta.fee, meta.receive_time - now}); backlog.push_back({meta.blob_size, meta.fee, meta.receive_time - now});
return true; return true;
}); }, false, include_unrelayed_txes);
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
void tx_memory_pool::get_transaction_stats(struct txpool_stats& stats) const void tx_memory_pool::get_transaction_stats(struct txpool_stats& stats, bool include_unrelayed_txes) const
{ {
CRITICAL_REGION_LOCAL(m_transactions_lock); CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain); CRITICAL_REGION_LOCAL1(m_blockchain);
const uint64_t now = time(NULL); const uint64_t now = time(NULL);
std::map<uint64_t, txpool_histo> agebytes; std::map<uint64_t, txpool_histo> agebytes;
stats.txs_total = m_blockchain.get_txpool_tx_count(); stats.txs_total = m_blockchain.get_txpool_tx_count(include_unrelayed_txes);
std::vector<uint32_t> sizes; std::vector<uint32_t> sizes;
sizes.reserve(stats.txs_total); sizes.reserve(stats.txs_total);
m_blockchain.for_all_txpool_txes([&stats, &sizes, now, &agebytes](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){ m_blockchain.for_all_txpool_txes([&stats, &sizes, now, &agebytes](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
@ -595,7 +595,7 @@ namespace cryptonote
agebytes[age].txs++; agebytes[age].txs++;
agebytes[age].bytes += meta.blob_size; agebytes[age].bytes += meta.blob_size;
return true; return true;
}); }, false, include_unrelayed_txes);
stats.bytes_med = epee::misc_utils::median(sizes); stats.bytes_med = epee::misc_utils::median(sizes);
if (stats.txs_total > 1) if (stats.txs_total > 1)
{ {
@ -642,11 +642,11 @@ namespace cryptonote
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
//TODO: investigate whether boolean return is appropriate //TODO: investigate whether boolean return is appropriate
bool tx_memory_pool::get_transactions_and_spent_keys_info(std::vector<tx_info>& tx_infos, std::vector<spent_key_image_info>& key_image_infos) const bool tx_memory_pool::get_transactions_and_spent_keys_info(std::vector<tx_info>& tx_infos, std::vector<spent_key_image_info>& key_image_infos, bool include_sensitive_data) const
{ {
CRITICAL_REGION_LOCAL(m_transactions_lock); CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain); CRITICAL_REGION_LOCAL1(m_blockchain);
m_blockchain.for_all_txpool_txes([&tx_infos, key_image_infos](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){ m_blockchain.for_all_txpool_txes([&tx_infos, key_image_infos, include_sensitive_data](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
tx_info txi; tx_info txi;
txi.id_hash = epee::string_tools::pod_to_hex(txid); txi.id_hash = epee::string_tools::pod_to_hex(txid);
transaction tx; transaction tx;
@ -664,14 +664,17 @@ namespace cryptonote
txi.max_used_block_id_hash = epee::string_tools::pod_to_hex(meta.max_used_block_id); txi.max_used_block_id_hash = epee::string_tools::pod_to_hex(meta.max_used_block_id);
txi.last_failed_height = meta.last_failed_height; txi.last_failed_height = meta.last_failed_height;
txi.last_failed_id_hash = epee::string_tools::pod_to_hex(meta.last_failed_id); txi.last_failed_id_hash = epee::string_tools::pod_to_hex(meta.last_failed_id);
txi.receive_time = meta.receive_time; // In restricted mode we do not include this data:
txi.receive_time = include_sensitive_data ? meta.receive_time : 0;
txi.relayed = meta.relayed; txi.relayed = meta.relayed;
txi.last_relayed_time = meta.last_relayed_time; // In restricted mode we do not include this data:
txi.last_relayed_time = include_sensitive_data ? meta.last_relayed_time : 0;
txi.do_not_relay = meta.do_not_relay; txi.do_not_relay = meta.do_not_relay;
tx_infos.push_back(txi); tx_infos.push_back(txi);
return true; return true;
}, true); }, true, include_sensitive_data);
txpool_tx_meta_t meta;
for (const key_images_container::value_type& kee : m_spent_key_images) { for (const key_images_container::value_type& kee : m_spent_key_images) {
const crypto::key_image& k_image = kee.first; const crypto::key_image& k_image = kee.first;
const std::unordered_set<crypto::hash>& kei_image_set = kee.second; const std::unordered_set<crypto::hash>& kei_image_set = kee.second;
@ -679,9 +682,26 @@ namespace cryptonote
ki.id_hash = epee::string_tools::pod_to_hex(k_image); ki.id_hash = epee::string_tools::pod_to_hex(k_image);
for (const crypto::hash& tx_id_hash : kei_image_set) for (const crypto::hash& tx_id_hash : kei_image_set)
{ {
if (!include_sensitive_data)
{
try
{
meta = m_blockchain.get_txpool_tx_meta(tx_id_hash);
if (!meta.relayed)
// Do not include that transaction if in restricted mode and it's not relayed
continue;
}
catch (const std::exception &e)
{
MERROR("Failed to get tx meta from txpool: " << e.what());
return false;
}
}
ki.txs_hashes.push_back(epee::string_tools::pod_to_hex(tx_id_hash)); ki.txs_hashes.push_back(epee::string_tools::pod_to_hex(tx_id_hash));
} }
key_image_infos.push_back(ki); // Only return key images for which we have at least one tx that we can show for them
if (!ki.txs_hashes.empty())
key_image_infos.push_back(ki);
} }
return true; return true;
} }
@ -714,7 +734,7 @@ namespace cryptonote
txi.do_not_relay = meta.do_not_relay; txi.do_not_relay = meta.do_not_relay;
tx_infos.push_back(txi); tx_infos.push_back(txi);
return true; return true;
}, true); }, true, false);
for (const key_images_container::value_type& kee : m_spent_key_images) { for (const key_images_container::value_type& kee : m_spent_key_images) {
std::vector<crypto::hash> tx_hashes; std::vector<crypto::hash> tx_hashes;
@ -1044,7 +1064,7 @@ namespace cryptonote
remove.insert(txid); remove.insert(txid);
} }
return true; return true;
}); }, false);
size_t n_removed = 0; size_t n_removed = 0;
if (!remove.empty()) if (!remove.empty())

View File

@ -233,29 +233,37 @@ namespace cryptonote
* @brief get a list of all transactions in the pool * @brief get a list of all transactions in the pool
* *
* @param txs return-by-reference the list of transactions * @param txs return-by-reference the list of transactions
* @param include_unrelayed_txes include unrelayed txes in the result
*
*/ */
void get_transactions(std::list<transaction>& txs) const; void get_transactions(std::list<transaction>& txs, bool include_unrelayed_txes = true) const;
/** /**
* @brief get a list of all transaction hashes in the pool * @brief get a list of all transaction hashes in the pool
* *
* @param txs return-by-reference the list of transactions * @param txs return-by-reference the list of transactions
* @param include_unrelayed_txes include unrelayed txes in the result
*
*/ */
void get_transaction_hashes(std::vector<crypto::hash>& txs) const; void get_transaction_hashes(std::vector<crypto::hash>& txs, bool include_unrelayed_txes = true) const;
/** /**
* @brief get (size, fee, receive time) for all transaction in the pool * @brief get (size, fee, receive time) for all transaction in the pool
* *
* @param txs return-by-reference that data * @param txs return-by-reference that data
* @param include_unrelayed_txes include unrelayed txes in the result
*
*/ */
void get_transaction_backlog(std::vector<tx_backlog_entry>& backlog) const; void get_transaction_backlog(std::vector<tx_backlog_entry>& backlog, bool include_unrelayed_txes = true) const;
/** /**
* @brief get a summary statistics of all transaction hashes in the pool * @brief get a summary statistics of all transaction hashes in the pool
* *
* @param stats return-by-reference the pool statistics * @param stats return-by-reference the pool statistics
* @param include_unrelayed_txes include unrelayed txes in the result
*
*/ */
void get_transaction_stats(struct txpool_stats& stats) const; void get_transaction_stats(struct txpool_stats& stats, bool include_unrelayed_txes = true) const;
/** /**
* @brief get information about all transactions and key images in the pool * @brief get information about all transactions and key images in the pool
@ -264,10 +272,11 @@ namespace cryptonote
* *
* @param tx_infos return-by-reference the transactions' information * @param tx_infos return-by-reference the transactions' information
* @param key_image_infos return-by-reference the spent key images' information * @param key_image_infos return-by-reference the spent key images' information
* @param include_sensitive_data include unrelayed txes and fields that are sensitive to the node privacy
* *
* @return true * @return true
*/ */
bool get_transactions_and_spent_keys_info(std::vector<tx_info>& tx_infos, std::vector<spent_key_image_info>& key_image_infos) const; bool get_transactions_and_spent_keys_info(std::vector<tx_info>& tx_infos, std::vector<spent_key_image_info>& key_image_infos, bool include_sensitive_data = true) const;
/** /**
* @brief get information about all transactions and key images in the pool * @brief get information about all transactions and key images in the pool
@ -308,6 +317,7 @@ namespace cryptonote
* nonzero fee * nonzero fee
* hasn't been relayed too recently * hasn't been relayed too recently
* isn't old enough that relaying it is considered harmful * isn't old enough that relaying it is considered harmful
* Note a transaction can be "relayable" even if do_not_relay is true
* *
* @param txs return-by-reference the transactions and their hashes * @param txs return-by-reference the transactions and their hashes
* *
@ -327,7 +337,7 @@ namespace cryptonote
* *
* @return the number of transactions in the pool * @return the number of transactions in the pool
*/ */
size_t get_transactions_count() const; size_t get_transactions_count(bool include_unrelayed_txes = true) const;
/** /**
* @brief get a string containing human-readable pool information * @brief get a string containing human-readable pool information

View File

@ -814,7 +814,7 @@ bool t_rpc_command_executor::print_transaction_pool_long() {
} }
else else
{ {
if (!m_rpc_server->on_get_transaction_pool(req, res) || res.status != CORE_RPC_STATUS_OK) if (!m_rpc_server->on_get_transaction_pool(req, res, false) || res.status != CORE_RPC_STATUS_OK)
{ {
tools::fail_msg_writer() << make_error(fail_message, res.status); tools::fail_msg_writer() << make_error(fail_message, res.status);
return true; return true;
@ -898,7 +898,7 @@ bool t_rpc_command_executor::print_transaction_pool_short() {
} }
else else
{ {
if (!m_rpc_server->on_get_transaction_pool(req, res) || res.status != CORE_RPC_STATUS_OK) if (!m_rpc_server->on_get_transaction_pool(req, res, false) || res.status != CORE_RPC_STATUS_OK)
{ {
tools::fail_msg_writer() << make_error(fail_message, res.status); tools::fail_msg_writer() << make_error(fail_message, res.status);
return true; return true;
@ -954,7 +954,7 @@ bool t_rpc_command_executor::print_transaction_pool_stats() {
else else
{ {
memset(&res.pool_stats, 0, sizeof(res.pool_stats)); memset(&res.pool_stats, 0, sizeof(res.pool_stats));
if (!m_rpc_server->on_get_transaction_pool_stats(req, res) || res.status != CORE_RPC_STATUS_OK) if (!m_rpc_server->on_get_transaction_pool_stats(req, res, false) || res.status != CORE_RPC_STATUS_OK)
{ {
tools::fail_msg_writer() << make_error(fail_message, res.status); tools::fail_msg_writer() << make_error(fail_message, res.status);
return true; return true;

View File

@ -564,7 +564,7 @@ namespace cryptonote
return true; return true;
} }
//------------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_is_key_image_spent(const COMMAND_RPC_IS_KEY_IMAGE_SPENT::request& req, COMMAND_RPC_IS_KEY_IMAGE_SPENT::response& res) bool core_rpc_server::on_is_key_image_spent(const COMMAND_RPC_IS_KEY_IMAGE_SPENT::request& req, COMMAND_RPC_IS_KEY_IMAGE_SPENT::response& res, bool request_has_rpc_origin)
{ {
CHECK_CORE_BUSY(); CHECK_CORE_BUSY();
std::vector<crypto::key_image> key_images; std::vector<crypto::key_image> key_images;
@ -596,7 +596,7 @@ namespace cryptonote
// check the pool too // check the pool too
std::vector<cryptonote::tx_info> txs; std::vector<cryptonote::tx_info> txs;
std::vector<cryptonote::spent_key_image_info> ki; std::vector<cryptonote::spent_key_image_info> ki;
r = m_core.get_pool_transactions_and_spent_keys_info(txs, ki); r = m_core.get_pool_transactions_and_spent_keys_info(txs, ki, !request_has_rpc_origin || !m_restricted);
if(!r) if(!r)
{ {
res.status = "Failed"; res.status = "Failed";
@ -843,26 +843,26 @@ namespace cryptonote
return true; return true;
} }
//------------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_transaction_pool(const COMMAND_RPC_GET_TRANSACTION_POOL::request& req, COMMAND_RPC_GET_TRANSACTION_POOL::response& res) bool core_rpc_server::on_get_transaction_pool(const COMMAND_RPC_GET_TRANSACTION_POOL::request& req, COMMAND_RPC_GET_TRANSACTION_POOL::response& res, bool request_has_rpc_origin)
{ {
CHECK_CORE_BUSY(); CHECK_CORE_BUSY();
m_core.get_pool_transactions_and_spent_keys_info(res.transactions, res.spent_key_images); m_core.get_pool_transactions_and_spent_keys_info(res.transactions, res.spent_key_images, !request_has_rpc_origin || !m_restricted);
res.status = CORE_RPC_STATUS_OK; res.status = CORE_RPC_STATUS_OK;
return true; return true;
} }
//------------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_transaction_pool_hashes(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response& res) bool core_rpc_server::on_get_transaction_pool_hashes(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response& res, bool request_has_rpc_origin)
{ {
CHECK_CORE_BUSY(); CHECK_CORE_BUSY();
m_core.get_pool_transaction_hashes(res.tx_hashes); m_core.get_pool_transaction_hashes(res.tx_hashes, !request_has_rpc_origin || !m_restricted);
res.status = CORE_RPC_STATUS_OK; res.status = CORE_RPC_STATUS_OK;
return true; return true;
} }
//------------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_transaction_pool_stats(const COMMAND_RPC_GET_TRANSACTION_POOL_STATS::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_STATS::response& res) bool core_rpc_server::on_get_transaction_pool_stats(const COMMAND_RPC_GET_TRANSACTION_POOL_STATS::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_STATS::response& res, bool request_has_rpc_origin)
{ {
CHECK_CORE_BUSY(); CHECK_CORE_BUSY();
m_core.get_pool_transaction_stats(res.pool_stats); m_core.get_pool_transaction_stats(res.pool_stats, !request_has_rpc_origin || !m_restricted);
res.status = CORE_RPC_STATUS_OK; res.status = CORE_RPC_STATUS_OK;
return true; return true;
} }
@ -1825,7 +1825,7 @@ namespace cryptonote
const command_line::arg_descriptor<bool> core_rpc_server::arg_restricted_rpc = { const command_line::arg_descriptor<bool> core_rpc_server::arg_restricted_rpc = {
"restricted-rpc" "restricted-rpc"
, "Restrict RPC to view only commands" , "Restrict RPC to view only commands and do not return privacy sensitive data in RPC calls"
, false , false
}; };
} // namespace cryptonote } // namespace cryptonote

View File

@ -137,7 +137,7 @@ namespace cryptonote
bool on_get_blocks_by_height(const COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::response& res); bool on_get_blocks_by_height(const COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::response& res);
bool on_get_hashes(const COMMAND_RPC_GET_HASHES_FAST::request& req, COMMAND_RPC_GET_HASHES_FAST::response& res); bool on_get_hashes(const COMMAND_RPC_GET_HASHES_FAST::request& req, COMMAND_RPC_GET_HASHES_FAST::response& res);
bool on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res); bool on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res);
bool on_is_key_image_spent(const COMMAND_RPC_IS_KEY_IMAGE_SPENT::request& req, COMMAND_RPC_IS_KEY_IMAGE_SPENT::response& res); bool on_is_key_image_spent(const COMMAND_RPC_IS_KEY_IMAGE_SPENT::request& req, COMMAND_RPC_IS_KEY_IMAGE_SPENT::response& res, bool request_has_rpc_origin = true);
bool on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res); bool on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res);
bool on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMMAND_RPC_SEND_RAW_TX::response& res); bool on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMMAND_RPC_SEND_RAW_TX::response& res);
bool on_start_mining(const COMMAND_RPC_START_MINING::request& req, COMMAND_RPC_START_MINING::response& res); bool on_start_mining(const COMMAND_RPC_START_MINING::request& req, COMMAND_RPC_START_MINING::response& res);
@ -153,9 +153,9 @@ namespace cryptonote
bool on_set_log_hash_rate(const COMMAND_RPC_SET_LOG_HASH_RATE::request& req, COMMAND_RPC_SET_LOG_HASH_RATE::response& res); bool on_set_log_hash_rate(const COMMAND_RPC_SET_LOG_HASH_RATE::request& req, COMMAND_RPC_SET_LOG_HASH_RATE::response& res);
bool on_set_log_level(const COMMAND_RPC_SET_LOG_LEVEL::request& req, COMMAND_RPC_SET_LOG_LEVEL::response& res); bool on_set_log_level(const COMMAND_RPC_SET_LOG_LEVEL::request& req, COMMAND_RPC_SET_LOG_LEVEL::response& res);
bool on_set_log_categories(const COMMAND_RPC_SET_LOG_CATEGORIES::request& req, COMMAND_RPC_SET_LOG_CATEGORIES::response& res); bool on_set_log_categories(const COMMAND_RPC_SET_LOG_CATEGORIES::request& req, COMMAND_RPC_SET_LOG_CATEGORIES::response& res);
bool on_get_transaction_pool(const COMMAND_RPC_GET_TRANSACTION_POOL::request& req, COMMAND_RPC_GET_TRANSACTION_POOL::response& res); bool on_get_transaction_pool(const COMMAND_RPC_GET_TRANSACTION_POOL::request& req, COMMAND_RPC_GET_TRANSACTION_POOL::response& res, bool request_has_rpc_origin = true);
bool on_get_transaction_pool_hashes(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response& res); bool on_get_transaction_pool_hashes(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response& res, bool request_has_rpc_origin = true);
bool on_get_transaction_pool_stats(const COMMAND_RPC_GET_TRANSACTION_POOL_STATS::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_STATS::response& res); bool on_get_transaction_pool_stats(const COMMAND_RPC_GET_TRANSACTION_POOL_STATS::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_STATS::response& res, bool request_has_rpc_origin = true);
bool on_stop_daemon(const COMMAND_RPC_STOP_DAEMON::request& req, COMMAND_RPC_STOP_DAEMON::response& res); bool on_stop_daemon(const COMMAND_RPC_STOP_DAEMON::request& req, COMMAND_RPC_STOP_DAEMON::response& res);
bool on_get_limit(const COMMAND_RPC_GET_LIMIT::request& req, COMMAND_RPC_GET_LIMIT::response& res); bool on_get_limit(const COMMAND_RPC_GET_LIMIT::request& req, COMMAND_RPC_GET_LIMIT::response& res);
bool on_set_limit(const COMMAND_RPC_SET_LIMIT::request& req, COMMAND_RPC_SET_LIMIT::response& res); bool on_set_limit(const COMMAND_RPC_SET_LIMIT::request& req, COMMAND_RPC_SET_LIMIT::response& res);

View File

@ -115,13 +115,13 @@ public:
virtual void add_txpool_tx(const transaction &tx, const txpool_tx_meta_t& details) {} virtual void add_txpool_tx(const transaction &tx, const txpool_tx_meta_t& details) {}
virtual void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t& details) {} virtual void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t& details) {}
virtual uint64_t get_txpool_tx_count() const { return 0; } virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const { return 0; }
virtual bool txpool_has_tx(const crypto::hash &txid) const { return false; } virtual bool txpool_has_tx(const crypto::hash &txid) const { return false; }
virtual void remove_txpool_tx(const crypto::hash& txid) {} virtual void remove_txpool_tx(const crypto::hash& txid) {}
virtual txpool_tx_meta_t get_txpool_tx_meta(const crypto::hash& txid) const { return txpool_tx_meta_t(); } virtual txpool_tx_meta_t get_txpool_tx_meta(const crypto::hash& txid) const { return txpool_tx_meta_t(); }
virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const { return false; } virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const { return false; }
virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const { return ""; } virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const { return ""; }
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false) const { return false; } 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 = false) const { return false; }
virtual void add_block( const block& blk virtual void add_block( const block& blk
, const size_t& block_size , const size_t& block_size