aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt6
-rw-r--r--src/blockchain_db/blockchain_db.cpp84
-rw-r--r--src/blockchain_db/blockchain_db.h49
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp48
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h10
-rw-r--r--src/blockchain_db/testdb.h10
-rw-r--r--src/blockchain_utilities/blockchain_import.cpp2
-rw-r--r--src/common/threadpool.cpp31
-rw-r--r--src/common/threadpool.h5
-rw-r--r--src/crypto/blake256.c9
-rw-r--r--src/cryptonote_core/blockchain.cpp38
-rw-r--r--src/cryptonote_core/blockchain.h11
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp120
-rw-r--r--src/cryptonote_core/cryptonote_core.h73
-rw-r--r--src/cryptonote_core/i_core_events.h44
-rw-r--r--src/cryptonote_core/tx_pool.cpp213
-rw-r--r--src/cryptonote_core/tx_pool.h53
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.h2
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl34
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler_common.h4
-rw-r--r--src/cryptonote_protocol/enums.h43
-rw-r--r--src/cryptonote_protocol/fwd.h37
-rw-r--r--src/cryptonote_protocol/levin_notify.h6
-rw-r--r--src/daemon/command_parser_executor.cpp4
-rw-r--r--src/daemon/rpc_command_executor.cpp38
-rw-r--r--src/daemon/rpc_command_executor.h2
-rw-r--r--src/daemonizer/posix_fork.cpp7
-rw-r--r--src/p2p/net_node.h3
-rw-r--r--src/p2p/net_node.inl12
-rw-r--r--src/p2p/net_node_common.h6
-rw-r--r--src/ringct/bulletproofs.cc61
-rw-r--r--src/ringct/rctTypes.cpp38
-rw-r--r--src/rpc/CMakeLists.txt2
-rw-r--r--src/rpc/core_rpc_server.cpp16
-rw-r--r--src/rpc/daemon_handler.cpp22
-rw-r--r--src/rpc/rpc_version_str.cpp55
-rw-r--r--src/rpc/rpc_version_str.h43
-rw-r--r--src/simplewallet/simplewallet.cpp28
-rw-r--r--src/wallet/CMakeLists.txt65
-rw-r--r--src/wallet/node_rpc_proxy.cpp2
-rw-r--r--src/wallet/wallet2.cpp42
-rw-r--r--src/wallet/wallet2.h4
-rw-r--r--src/wallet/wallet_rpc_server.cpp45
-rw-r--r--src/wallet/wallet_rpc_server.h2
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h45
45 files changed, 1028 insertions, 446 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f332af3d3..d45363e24 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -113,12 +113,10 @@ add_subdirectory(lmdb)
add_subdirectory(multisig)
add_subdirectory(net)
add_subdirectory(hardforks)
-if(NOT IOS)
- add_subdirectory(blockchain_db)
-endif()
+add_subdirectory(blockchain_db)
add_subdirectory(mnemonics)
+add_subdirectory(rpc)
if(NOT IOS)
- add_subdirectory(rpc)
add_subdirectory(serialization)
endif()
add_subdirectory(wallet)
diff --git a/src/blockchain_db/blockchain_db.cpp b/src/blockchain_db/blockchain_db.cpp
index 63ac38a88..5fec22d8d 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::flood:
+ 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::flood:
+ 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::flood;
+}
+
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 d1e4919be..b2c5d6cb4 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/flooding/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
@@ -1465,12 +1487,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
@@ -1494,10 +1516,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
@@ -1506,7 +1529,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
@@ -1604,7 +1637,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 f978ef307..e8667adcf 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -1771,7 +1771,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 +1781,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 +1807,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 +1816,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 +1825,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 +1893,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 +1903,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 +1929,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 +2270,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 +2294,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 61a551476..e56711e8f 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -281,12 +281,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();
@@ -298,7 +298,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 ac19fae25..a5847dec6 100644
--- a/src/blockchain_db/testdb.h
+++ b/src/blockchain_db/testdb.h
@@ -126,14 +126,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
diff --git a/src/blockchain_utilities/blockchain_import.cpp b/src/blockchain_utilities/blockchain_import.cpp
index 5d039d7f4..852e9cf4f 100644
--- a/src/blockchain_utilities/blockchain_import.cpp
+++ b/src/blockchain_utilities/blockchain_import.cpp
@@ -174,7 +174,7 @@ int check_flush(cryptonote::core &core, std::vector<block_complete_entry> &block
for(auto& tx_blob: block_entry.txs)
{
tx_verification_context tvc = AUTO_VAL_INIT(tvc);
- core.handle_incoming_tx(tx_blob, tvc, true, true, false);
+ core.handle_incoming_tx(tx_blob, tvc, relay_method::block, true);
if(tvc.m_verifivation_failed)
{
MERROR("transaction verification failed, tx_id = "
diff --git a/src/common/threadpool.cpp b/src/common/threadpool.cpp
index 2748c798c..18204eeee 100644
--- a/src/common/threadpool.cpp
+++ b/src/common/threadpool.cpp
@@ -37,16 +37,14 @@ static __thread bool is_leaf = false;
namespace tools
{
threadpool::threadpool(unsigned int max_threads) : running(true), active(0) {
- boost::thread::attributes attrs;
- attrs.set_stack_size(THREAD_STACK_SIZE);
- max = max_threads ? max_threads : tools::get_max_concurrency();
- size_t i = max ? max - 1 : 0;
- while(i--) {
- threads.push_back(boost::thread(attrs, boost::bind(&threadpool::run, this, false)));
- }
+ create(max_threads);
}
threadpool::~threadpool() {
+ destroy();
+}
+
+void threadpool::destroy() {
try
{
const boost::unique_lock<boost::mutex> lock(mutex);
@@ -64,6 +62,23 @@ threadpool::~threadpool() {
try { threads[i].join(); }
catch (...) { /* ignore */ }
}
+ threads.clear();
+}
+
+void threadpool::recycle() {
+ destroy();
+ create(max);
+}
+
+void threadpool::create(unsigned int max_threads) {
+ boost::thread::attributes attrs;
+ attrs.set_stack_size(THREAD_STACK_SIZE);
+ max = max_threads ? max_threads : tools::get_max_concurrency();
+ size_t i = max ? max - 1 : 0;
+ running = true;
+ while(i--) {
+ threads.push_back(boost::thread(attrs, boost::bind(&threadpool::run, this, false)));
+ }
}
void threadpool::submit(waiter *obj, std::function<void()> f, bool leaf) {
@@ -145,7 +160,7 @@ void threadpool::run(bool flush) {
if (!running) break;
active++;
- e = queue.front();
+ e = std::move(queue.front());
queue.pop_front();
lock.unlock();
++depth;
diff --git a/src/common/threadpool.h b/src/common/threadpool.h
index 5e490ee7d..a49d0e14f 100644
--- a/src/common/threadpool.h
+++ b/src/common/threadpool.h
@@ -69,12 +69,17 @@ public:
// task to finish.
void submit(waiter *waiter, std::function<void()> f, bool leaf = false);
+ // destroy and recreate threads
+ void recycle();
+
unsigned int get_max_concurrency() const;
~threadpool();
private:
threadpool(unsigned int max_threads = 0);
+ void destroy();
+ void create(unsigned int max_threads);
typedef struct entry {
waiter *wo;
std::function<void()> f;
diff --git a/src/crypto/blake256.c b/src/crypto/blake256.c
index 1e305b3a6..bb2c5fb40 100644
--- a/src/crypto/blake256.c
+++ b/src/crypto/blake256.c
@@ -40,6 +40,7 @@
#include <string.h>
#include <stdio.h>
#include <stdint.h>
+#include <memwipe.h>
#include "blake256.h"
#define U8TO32(p) \
@@ -277,7 +278,7 @@ void hmac_blake256_init(hmac_state *S, const uint8_t *_key, uint64_t keylen) {
}
blake256_update(&S->outer, pad, 512);
- memset(keyhash, 0, 32);
+ memwipe(keyhash, sizeof(keyhash));
}
// keylen = number of bytes
@@ -307,7 +308,7 @@ void hmac_blake224_init(hmac_state *S, const uint8_t *_key, uint64_t keylen) {
}
blake224_update(&S->outer, pad, 512);
- memset(keyhash, 0, 32);
+ memwipe(keyhash, sizeof(keyhash));
}
// datalen = number of bits
@@ -327,7 +328,7 @@ void hmac_blake256_final(hmac_state *S, uint8_t *digest) {
blake256_final(&S->inner, ihash);
blake256_update(&S->outer, ihash, 256);
blake256_final(&S->outer, digest);
- memset(ihash, 0, 32);
+ memwipe(ihash, sizeof(ihash));
}
void hmac_blake224_final(hmac_state *S, uint8_t *digest) {
@@ -335,7 +336,7 @@ void hmac_blake224_final(hmac_state *S, uint8_t *digest) {
blake224_final(&S->inner, ihash);
blake224_update(&S->outer, ihash, 224);
blake224_final(&S->outer, digest);
- memset(ihash, 0, 32);
+ memwipe(ihash, sizeof(ihash));
}
// keylen = number of bytes; inlen = number of bytes
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index d22158dfc..5070cc169 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -616,7 +616,7 @@ block Blockchain::pop_block_from_blockchain()
// that might not be always true. Unlikely though, and always relaying
// these again might cause a spike of traffic as many nodes re-relay
// all the transactions in a popped block when a reorg happens.
- bool r = m_tx_pool.add_tx(tx, tvc, true, true, false, version);
+ bool r = m_tx_pool.add_tx(tx, tvc, relay_method::block, true, version);
if (!r)
{
LOG_ERROR("Error returning transaction to tx_pool");
@@ -1765,7 +1765,7 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
{
cryptonote::tx_memory_pool::tx_details td;
cryptonote::blobdata blob;
- if (m_tx_pool.have_tx(txid))
+ if (m_tx_pool.have_tx(txid, relay_category::legacy))
{
if (m_tx_pool.get_transaction_info(txid, td))
{
@@ -3641,7 +3641,7 @@ void Blockchain::return_tx_to_pool(std::vector<std::pair<transaction, blobdata>>
// all the transactions in a popped block when a reorg happens.
const size_t weight = get_transaction_weight(tx.first, tx.second.size());
const crypto::hash tx_hash = get_transaction_hash(tx.first);
- if (!m_tx_pool.add_tx(tx.first, tx_hash, tx.second, weight, tvc, true, true, false, version))
+ if (!m_tx_pool.add_tx(tx.first, tx_hash, tx.second, weight, tvc, relay_method::block, true, version))
{
MERROR("Failed to return taken transaction with hash: " << get_transaction_hash(tx.first) << " to tx_pool");
}
@@ -3661,7 +3661,7 @@ bool Blockchain::flush_txes_from_pool(const std::vector<crypto::hash> &txids)
uint64_t fee;
bool relayed, do_not_relay, double_spend_seen, pruned;
MINFO("Removing txid " << txid << " from the pool");
- if(m_tx_pool.have_tx(txid) && !m_tx_pool.take_tx(txid, tx, txblob, tx_weight, fee, relayed, do_not_relay, double_spend_seen, pruned))
+ if(!m_tx_pool.have_tx(txid, relay_category::all) && !m_tx_pool.take_tx(txid, tx, txblob, tx_weight, fee, relayed, do_not_relay, double_spend_seen, pruned))
{
MERROR("Failed to remove txid " << txid << " from the pool");
res = false;
@@ -4895,9 +4895,9 @@ void Blockchain::remove_txpool_tx(const crypto::hash &txid)
m_db->remove_txpool_tx(txid);
}
-uint64_t Blockchain::get_txpool_tx_count(bool include_unrelayed_txes) const
+uint64_t Blockchain::get_txpool_tx_count(bool include_sensitive) const
{
- return m_db->get_txpool_tx_count(include_unrelayed_txes);
+ return m_db->get_txpool_tx_count(include_sensitive ? relay_category::all : relay_category::broadcasted);
}
bool Blockchain::get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const
@@ -4905,19 +4905,24 @@ bool Blockchain::get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &
return m_db->get_txpool_tx_meta(txid, meta);
}
-bool Blockchain::get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const
+bool Blockchain::get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd, relay_category tx_category) const
{
- return m_db->get_txpool_tx_blob(txid, bd);
+ return m_db->get_txpool_tx_blob(txid, bd, tx_category);
}
-cryptonote::blobdata Blockchain::get_txpool_tx_blob(const crypto::hash& txid) const
+cryptonote::blobdata Blockchain::get_txpool_tx_blob(const crypto::hash& txid, relay_category tx_category) const
{
- return m_db->get_txpool_tx_blob(txid);
+ return m_db->get_txpool_tx_blob(txid, tx_category);
}
-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
+bool Blockchain::for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob, relay_category tx_category) const
{
- return m_db->for_all_txpool_txes(f, include_blob, include_unrelayed_txes);
+ return m_db->for_all_txpool_txes(f, include_blob, tx_category);
+}
+
+bool Blockchain::txpool_tx_matches_category(const crypto::hash& tx_hash, relay_category category)
+{
+ return m_db->txpool_tx_matches_category(tx_hash, category);
}
void Blockchain::set_user_options(uint64_t maxthreads, bool sync_on_blocks, uint64_t sync_threshold, blockchain_db_sync_mode sync_mode, bool fast_sync)
@@ -5074,7 +5079,12 @@ void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get
return;
}
const size_t size_needed = 4 + nblocks * (sizeof(crypto::hash) * 2);
- if(nblocks > 0 && nblocks > (m_db->height() + HASH_OF_HASHES_STEP - 1) / HASH_OF_HASHES_STEP && checkpoints.size() >= size_needed)
+ if(checkpoints.size() != size_needed)
+ {
+ MERROR("Failed to load hashes - unexpected data size");
+ return;
+ }
+ else if(nblocks > 0 && nblocks > (m_db->height() + HASH_OF_HASHES_STEP - 1) / HASH_OF_HASHES_STEP)
{
p += sizeof(uint32_t);
m_blocks_hash_of_hashes.reserve(nblocks);
@@ -5098,7 +5108,7 @@ void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get
CRITICAL_REGION_LOCAL(m_tx_pool);
std::vector<transaction> txs;
- m_tx_pool.get_transactions(txs);
+ m_tx_pool.get_transactions(txs, true);
size_t tx_weight;
uint64_t fee;
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index 6467031c2..0aecdcb57 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -964,11 +964,12 @@ namespace cryptonote
void add_txpool_tx(const crypto::hash &txid, const cryptonote::blobdata &blob, 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);
- uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const;
+ uint64_t get_txpool_tx_count(bool include_sensitive = false) const;
bool get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) 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;
- 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 get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd, relay_category tx_category) const;
+ cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid, relay_category tx_category) const;
+ 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 tx_category = relay_category::broadcasted) const;
+ bool txpool_tx_matches_category(const crypto::hash& tx_hash, relay_category category);
bool is_within_compiled_block_hash_area() const { return is_within_compiled_block_hash_area(m_db->height()); }
uint64_t prevalidate_block_hashes(uint64_t height, const std::vector<crypto::hash> &hashes, const std::vector<uint64_t> &weights);
@@ -1042,7 +1043,7 @@ namespace cryptonote
std::unordered_map<crypto::hash, std::unordered_map<crypto::key_image, std::vector<output_data_t>>> m_scan_table;
std::unordered_map<crypto::hash, crypto::hash> m_blocks_longhash_table;
- // SHA-3 hashes for each block and for fast pow checking
+ // Keccak hashes for each block and for fast pow checking
std::vector<std::pair<crypto::hash, crypto::hash>> m_blocks_hash_of_hashes;
std::vector<std::pair<crypto::hash, uint64_t>> m_blocks_hash_check;
std::vector<crypto::hash> m_blocks_txs_check;
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 02620996e..cf23a652c 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -29,6 +29,7 @@
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#include <boost/algorithm/string.hpp>
+#include <boost/uuid/nil_generator.hpp>
#include "string_tools.h"
using namespace epee;
@@ -753,7 +754,7 @@ namespace cryptonote
return false;
}
//-----------------------------------------------------------------------------------------------
- bool core::handle_incoming_tx_pre(const tx_blob_entry& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash, bool keeped_by_block, bool relayed, bool do_not_relay)
+ bool core::handle_incoming_tx_pre(const tx_blob_entry& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash)
{
tvc = {};
@@ -817,7 +818,7 @@ namespace cryptonote
return true;
}
//-----------------------------------------------------------------------------------------------
- bool core::handle_incoming_tx_post(const tx_blob_entry& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash, bool keeped_by_block, bool relayed, bool do_not_relay)
+ bool core::handle_incoming_tx_post(const tx_blob_entry& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash)
{
if(!check_tx_syntax(tx))
{
@@ -946,23 +947,29 @@ namespace cryptonote
return ret;
}
//-----------------------------------------------------------------------------------------------
- bool core::handle_incoming_txs(const std::vector<tx_blob_entry>& tx_blobs, std::vector<tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
+ bool core::handle_incoming_txs(const epee::span<const tx_blob_entry> tx_blobs, epee::span<tx_verification_context> tvc, relay_method tx_relay, bool relayed)
{
TRY_ENTRY();
- CRITICAL_REGION_LOCAL(m_incoming_tx_lock);
+
+ if (tx_blobs.size() != tvc.size())
+ {
+ MERROR("tx_blobs and tx_verification_context spans must have equal size");
+ return false;
+ }
struct result { bool res; cryptonote::transaction tx; crypto::hash hash; };
std::vector<result> results(tx_blobs.size());
- tvc.resize(tx_blobs.size());
+ CRITICAL_REGION_LOCAL(m_incoming_tx_lock);
+
tools::threadpool& tpool = tools::threadpool::getInstance();
tools::threadpool::waiter waiter;
- std::vector<tx_blob_entry>::const_iterator it = tx_blobs.begin();
+ epee::span<tx_blob_entry>::const_iterator it = tx_blobs.begin();
for (size_t i = 0; i < tx_blobs.size(); i++, ++it) {
tpool.submit(&waiter, [&, i, it] {
try
{
- results[i].res = handle_incoming_tx_pre(*it, tvc[i], results[i].tx, results[i].hash, keeped_by_block, relayed, do_not_relay);
+ results[i].res = handle_incoming_tx_pre(*it, tvc[i], results[i].tx, results[i].hash);
}
catch (const std::exception &e)
{
@@ -978,7 +985,7 @@ namespace cryptonote
for (size_t i = 0; i < tx_blobs.size(); i++, ++it) {
if (!results[i].res)
continue;
- if(m_mempool.have_tx(results[i].hash))
+ if(m_mempool.have_tx(results[i].hash, relay_category::legacy))
{
LOG_PRINT_L2("tx " << results[i].hash << "already have transaction in tx_pool");
already_have[i] = true;
@@ -993,7 +1000,7 @@ namespace cryptonote
tpool.submit(&waiter, [&, i, it] {
try
{
- results[i].res = handle_incoming_tx_post(*it, tvc[i], results[i].tx, results[i].hash, keeped_by_block, relayed, do_not_relay);
+ results[i].res = handle_incoming_tx_post(*it, tvc[i], results[i].tx, results[i].hash);
}
catch (const std::exception &e)
{
@@ -1014,7 +1021,7 @@ namespace cryptonote
tx_info.push_back({&results[i].tx, results[i].hash, tvc[i], results[i].res});
}
if (!tx_info.empty())
- handle_incoming_tx_accumulated_batch(tx_info, keeped_by_block);
+ handle_incoming_tx_accumulated_batch(tx_info, tx_relay == relay_method::block);
bool ok = true;
it = tx_blobs.begin();
@@ -1024,13 +1031,14 @@ namespace cryptonote
ok = false;
continue;
}
- if (keeped_by_block)
+ if (tx_relay == relay_method::block)
get_blockchain_storage().on_new_tx_from_block(results[i].tx);
if (already_have[i])
continue;
const uint64_t weight = results[i].tx.pruned ? get_pruned_transaction_weight(results[i].tx) : get_transaction_weight(results[i].tx, it->blob.size());
- ok &= add_new_tx(results[i].tx, results[i].hash, tx_blobs[i].blob, weight, tvc[i], keeped_by_block, relayed, do_not_relay);
+ ok &= add_new_tx(results[i].tx, results[i].hash, tx_blobs[i].blob, weight, tvc[i], tx_relay, relayed);
+
if(tvc[i].m_verifivation_failed)
{MERROR_VER("Transaction verification failed: " << results[i].hash);}
else if(tvc[i].m_verifivation_impossible)
@@ -1044,19 +1052,9 @@ namespace cryptonote
CATCH_ENTRY_L0("core::handle_incoming_txs()", false);
}
//-----------------------------------------------------------------------------------------------
- bool core::handle_incoming_tx(const tx_blob_entry& tx_blob, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
- {
- std::vector<tx_blob_entry> tx_blobs;
- tx_blobs.push_back(tx_blob);
- std::vector<tx_verification_context> tvcv(1);
- bool r = handle_incoming_txs(tx_blobs, tvcv, keeped_by_block, relayed, do_not_relay);
- tvc = tvcv[0];
- return r;
- }
- //-----------------------------------------------------------------------------------------------
- bool core::handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
+ bool core::handle_incoming_tx(const tx_blob_entry& tx_blob, tx_verification_context& tvc, relay_method tx_relay, bool relayed)
{
- return handle_incoming_tx({tx_blob, crypto::null_hash}, tvc, keeped_by_block, relayed, do_not_relay);
+ return handle_incoming_txs({std::addressof(tx_blob), 1}, {std::addressof(tvc), 1}, tx_relay, relayed);
}
//-----------------------------------------------------------------------------------------------
bool core::get_stat_info(core_stat_info& st_inf) const
@@ -1246,13 +1244,13 @@ namespace cryptonote
return true;
}
//-----------------------------------------------------------------------------------------------
- bool core::add_new_tx(transaction& tx, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
+ bool core::add_new_tx(transaction& tx, tx_verification_context& tvc, relay_method tx_relay, bool relayed)
{
crypto::hash tx_hash = get_transaction_hash(tx);
blobdata bl;
t_serializable_object_to_blob(tx, bl);
size_t tx_weight = get_transaction_weight(tx, bl.size());
- return add_new_tx(tx, tx_hash, bl, tx_weight, tvc, keeped_by_block, relayed, do_not_relay);
+ return add_new_tx(tx, tx_hash, bl, tx_weight, tvc, tx_relay, relayed);
}
//-----------------------------------------------------------------------------------------------
size_t core::get_blockchain_total_transactions() const
@@ -1260,9 +1258,9 @@ namespace cryptonote
return m_blockchain_storage.get_total_transactions();
}
//-----------------------------------------------------------------------------------------------
- bool core::add_new_tx(transaction& tx, const crypto::hash& tx_hash, const cryptonote::blobdata &blob, size_t tx_weight, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
+ bool core::add_new_tx(transaction& tx, const crypto::hash& tx_hash, const cryptonote::blobdata &blob, size_t tx_weight, tx_verification_context& tvc, relay_method tx_relay, bool relayed)
{
- if(m_mempool.have_tx(tx_hash))
+ if(m_mempool.have_tx(tx_hash, relay_category::legacy))
{
LOG_PRINT_L2("tx " << tx_hash << "already have transaction in tx_pool");
return true;
@@ -1275,40 +1273,62 @@ namespace cryptonote
}
uint8_t version = m_blockchain_storage.get_current_hard_fork_version();
- return m_mempool.add_tx(tx, tx_hash, blob, tx_weight, tvc, keeped_by_block, relayed, do_not_relay, version);
+ return m_mempool.add_tx(tx, tx_hash, blob, tx_weight, tvc, tx_relay, relayed, version);
}
//-----------------------------------------------------------------------------------------------
bool core::relay_txpool_transactions()
{
// we attempt to relay txes that should be relayed, but were not
- std::vector<std::pair<crypto::hash, cryptonote::blobdata>> txs;
+ std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>> txs;
if (m_mempool.get_relayable_transactions(txs) && !txs.empty())
{
- cryptonote_connection_context fake_context = AUTO_VAL_INIT(fake_context);
- tx_verification_context tvc = AUTO_VAL_INIT(tvc);
- NOTIFY_NEW_TRANSACTIONS::request r;
- for (auto it = txs.begin(); it != txs.end(); ++it)
+ NOTIFY_NEW_TRANSACTIONS::request public_req{};
+ NOTIFY_NEW_TRANSACTIONS::request private_req{};
+ for (auto& tx : txs)
{
- r.txs.push_back(it->second);
+ switch (std::get<2>(tx))
+ {
+ default:
+ case relay_method::none:
+ break;
+ case relay_method::local:
+ private_req.txs.push_back(std::move(std::get<1>(tx)));
+ break;
+ case relay_method::block:
+ case relay_method::flood:
+ public_req.txs.push_back(std::move(std::get<1>(tx)));
+ break;
+ }
}
- get_protocol()->relay_transactions(r, fake_context);
- m_mempool.set_relayed(txs);
+
+ /* All txes are sent on randomized timers per connection in
+ `src/cryptonote_protocol/levin_notify.cpp.` They are either sent with
+ "white noise" delays or via diffusion (Dandelion++ fluff). So
+ re-relaying public and private _should_ be acceptable here. */
+ const boost::uuids::uuid source = boost::uuids::nil_uuid();
+ if (!public_req.txs.empty())
+ get_protocol()->relay_transactions(public_req, source, epee::net_utils::zone::public_);
+ if (!private_req.txs.empty())
+ get_protocol()->relay_transactions(private_req, source, epee::net_utils::zone::invalid);
}
return true;
}
//-----------------------------------------------------------------------------------------------
- void core::on_transaction_relayed(const cryptonote::blobdata& tx_blob)
+ void core::on_transactions_relayed(const epee::span<const cryptonote::blobdata> tx_blobs, const relay_method tx_relay)
{
- std::vector<std::pair<crypto::hash, cryptonote::blobdata>> txs;
- cryptonote::transaction tx;
- crypto::hash tx_hash;
- if (!parse_and_validate_tx_from_blob(tx_blob, tx, tx_hash))
+ std::vector<crypto::hash> tx_hashes{};
+ tx_hashes.resize(tx_blobs.size());
+
+ cryptonote::transaction tx{};
+ for (std::size_t i = 0; i < tx_blobs.size(); ++i)
{
- LOG_ERROR("Failed to parse relayed transaction");
- return;
+ if (!parse_and_validate_tx_from_blob(tx_blobs[i], tx, tx_hashes[i]))
+ {
+ LOG_ERROR("Failed to parse relayed transaction");
+ return;
+ }
}
- txs.push_back(std::make_pair(tx_hash, std::move(tx_blob)));
- m_mempool.set_relayed(txs);
+ m_mempool.set_relayed(epee::to_span(tx_hashes), tx_relay);
}
//-----------------------------------------------------------------------------------------------
bool core::get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce)
@@ -1369,7 +1389,7 @@ namespace cryptonote
for (const auto &tx_hash: b.tx_hashes)
{
cryptonote::blobdata txblob;
- CHECK_AND_ASSERT_THROW_MES(pool.get_transaction(tx_hash, txblob), "Transaction not found in pool");
+ CHECK_AND_ASSERT_THROW_MES(pool.get_transaction(tx_hash, txblob, relay_category::all), "Transaction not found in pool");
bce.txs.push_back({txblob, crypto::null_hash});
}
return bce;
@@ -1573,14 +1593,14 @@ namespace cryptonote
return true;
}
//-----------------------------------------------------------------------------------------------
- bool core::get_pool_transaction(const crypto::hash &id, cryptonote::blobdata& tx) const
+ bool core::get_pool_transaction(const crypto::hash &id, cryptonote::blobdata& tx, relay_category tx_category) const
{
- return m_mempool.get_transaction(id, tx);
+ return m_mempool.get_transaction(id, tx, tx_category);
}
//-----------------------------------------------------------------------------------------------
bool core::pool_has_tx(const crypto::hash &id) const
{
- return m_mempool.have_tx(id);
+ return m_mempool.have_tx(id, relay_category::legacy);
}
//-----------------------------------------------------------------------------------------------
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
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index f69ac3509..4b67984ab 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -35,7 +35,9 @@
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/variables_map.hpp>
+#include "cryptonote_core/i_core_events.h"
#include "cryptonote_protocol/cryptonote_protocol_handler_common.h"
+#include "cryptonote_protocol/enums.h"
#include "storages/portable_storage_template_helper.h"
#include "common/download.h"
#include "common/command_line.h"
@@ -46,6 +48,7 @@
#include "cryptonote_basic/cryptonote_stat_info.h"
#include "warnings.h"
#include "crypto/hash.h"
+#include "span.h"
PUSH_WARNINGS
DISABLE_VS_WARNINGS(4355)
@@ -77,7 +80,7 @@ namespace cryptonote
* limited to, communication among the Blockchain, the transaction pool,
* any miners, and the network.
*/
- class core: public i_miner_handler
+ class core final: public i_miner_handler, public i_core_events
{
public:
@@ -115,14 +118,12 @@ namespace cryptonote
*
* @param tx_blob the tx to handle
* @param tvc metadata about the transaction's validity
- * @param keeped_by_block if the transaction has been in a block
+ * @param tx_relay how the transaction was received
* @param relayed whether or not the transaction was relayed to us
- * @param do_not_relay whether to prevent the transaction from being relayed
*
* @return true if the transaction was accepted, false otherwise
*/
- bool handle_incoming_tx(const tx_blob_entry& tx_blob, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
- bool handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
+ bool handle_incoming_tx(const tx_blob_entry& tx_blob, tx_verification_context& tvc, relay_method tx_relay, bool relayed);
/**
* @brief handles a list of incoming transactions
@@ -130,15 +131,35 @@ namespace cryptonote
* Parses incoming transactions and, if nothing is obviously wrong,
* passes them along to the transaction pool
*
+ * @pre `tx_blobs.size() == tvc.size()`
+ *
* @param tx_blobs the txs to handle
* @param tvc metadata about the transactions' validity
- * @param keeped_by_block if the transactions have been in a block
+ * @param tx_relay how the transaction was received.
* @param relayed whether or not the transactions were relayed to us
- * @param do_not_relay whether to prevent the transactions from being relayed
*
* @return true if the transactions were accepted, false otherwise
*/
- bool handle_incoming_txs(const std::vector<tx_blob_entry>& tx_blobs, std::vector<tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
+ bool handle_incoming_txs(epee::span<const tx_blob_entry> tx_blobs, epee::span<tx_verification_context> tvc, relay_method tx_relay, bool relayed);
+
+ /**
+ * @brief handles a list of incoming transactions
+ *
+ * Parses incoming transactions and, if nothing is obviously wrong,
+ * passes them along to the transaction pool
+ *
+ * @param tx_blobs the txs to handle
+ * @param tvc metadata about the transactions' validity
+ * @param tx_relay how the transaction was received.
+ * @param relayed whether or not the transactions were relayed to us
+ *
+ * @return true if the transactions were accepted, false otherwise
+ */
+ bool handle_incoming_txs(const std::vector<tx_blob_entry>& tx_blobs, std::vector<tx_verification_context>& tvc, relay_method tx_relay, bool relayed)
+ {
+ tvc.resize(tx_blobs.size());
+ return handle_incoming_txs(epee::to_span(tx_blobs), epee::to_mut_span(tvc), tx_relay, relayed);
+ }
/**
* @brief handles an incoming block
@@ -212,9 +233,10 @@ namespace cryptonote
virtual bool get_block_template(block& b, const crypto::hash *prev_block, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce);
/**
- * @brief called when a transaction is relayed
+ * @brief called when a transaction is relayed.
+ * @note Should only be invoked from `levin_notify`.
*/
- virtual void on_transaction_relayed(const cryptonote::blobdata& tx);
+ virtual void on_transactions_relayed(epee::span<const cryptonote::blobdata> tx_blobs, relay_method tx_relay) final;
/**
@@ -440,11 +462,11 @@ namespace cryptonote
/**
* @copydoc tx_memory_pool::get_transactions
- * @param include_unrelayed_txes include unrelayed txes in result
+ * @param include_sensitive_txes include private transactions
*
* @note see tx_memory_pool::get_transactions
*/
- bool get_pool_transactions(std::vector<transaction>& txs, bool include_unrelayed_txes = true) const;
+ bool get_pool_transactions(std::vector<transaction>& txs, bool include_sensitive_txes = false) const;
/**
* @copydoc tx_memory_pool::get_txpool_backlog
@@ -455,34 +477,34 @@ namespace cryptonote
/**
* @copydoc tx_memory_pool::get_transactions
- * @param include_unrelayed_txes include unrelayed txes in result
+ * @param include_sensitive_txes include private transactions
*
* @note see tx_memory_pool::get_transactions
*/
- bool get_pool_transaction_hashes(std::vector<crypto::hash>& txs, bool include_unrelayed_txes = true) const;
+ bool get_pool_transaction_hashes(std::vector<crypto::hash>& txs, bool include_sensitive_txes = false) const;
/**
* @copydoc tx_memory_pool::get_transactions
- * @param include_unrelayed_txes include unrelayed txes in result
+ * @param include_sensitive_txes include private transactions
*
* @note see tx_memory_pool::get_transactions
*/
- bool get_pool_transaction_stats(struct txpool_stats& stats, bool include_unrelayed_txes = true) const;
+ bool get_pool_transaction_stats(struct txpool_stats& stats, bool include_sensitive_txes = false) const;
/**
* @copydoc tx_memory_pool::get_transaction
*
* @note see tx_memory_pool::get_transaction
*/
- bool get_pool_transaction(const crypto::hash& id, cryptonote::blobdata& tx) const;
+ bool get_pool_transaction(const crypto::hash& id, cryptonote::blobdata& tx, relay_category tx_category) const;
/**
* @copydoc tx_memory_pool::get_pool_transactions_and_spent_keys_info
- * @param include_unrelayed_txes include unrelayed txes in result
+ * @param include_sensitive_txes include private transactions
*
* @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, bool include_unrelayed_txes = true) 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_sensitive_txes = false) const;
/**
* @copydoc tx_memory_pool::get_pool_for_rpc
@@ -852,11 +874,11 @@ namespace cryptonote
* @param tx_hash the transaction's hash
* @param blob the transaction as a blob
* @param tx_weight the weight of the transaction
+ * @param tx_relay how the transaction was received
* @param relayed whether or not the transaction was relayed to us
- * @param do_not_relay whether to prevent the transaction from being relayed
*
*/
- bool add_new_tx(transaction& tx, const crypto::hash& tx_hash, const cryptonote::blobdata &blob, size_t tx_weight, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
+ bool add_new_tx(transaction& tx, const crypto::hash& tx_hash, const cryptonote::blobdata &blob, size_t tx_weight, tx_verification_context& tvc, relay_method tx_relay, bool relayed);
/**
* @brief add a new transaction to the transaction pool
@@ -865,15 +887,14 @@ namespace cryptonote
*
* @param tx the transaction to add
* @param tvc return-by-reference metadata about the transaction's verification process
- * @param keeped_by_block whether or not the transaction has been in a block
+ * @param tx_relay how the transaction was received
* @param relayed whether or not the transaction was relayed to us
- * @param do_not_relay whether to prevent the transaction from being relayed
*
* @return true if the transaction is already in the transaction pool,
* is already in a block on the Blockchain, or is successfully added
* to the transaction pool
*/
- bool add_new_tx(transaction& tx, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
+ bool add_new_tx(transaction& tx, tx_verification_context& tvc, relay_method tx_relay, bool relayed);
/**
* @copydoc Blockchain::add_new_block
@@ -929,8 +950,8 @@ namespace cryptonote
bool check_tx_semantic(const transaction& tx, bool keeped_by_block) const;
void set_semantics_failed(const crypto::hash &tx_hash);
- bool handle_incoming_tx_pre(const tx_blob_entry& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash, bool keeped_by_block, bool relayed, bool do_not_relay);
- bool handle_incoming_tx_post(const tx_blob_entry &tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash, bool keeped_by_block, bool relayed, bool do_not_relay);
+ bool handle_incoming_tx_pre(const tx_blob_entry& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash);
+ bool handle_incoming_tx_post(const tx_blob_entry& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash);
struct tx_verification_batch_info { const cryptonote::transaction *tx; crypto::hash tx_hash; tx_verification_context &tvc; bool &result; };
bool handle_incoming_tx_accumulated_batch(std::vector<tx_verification_batch_info> &tx_info, bool keeped_by_block);
diff --git a/src/cryptonote_core/i_core_events.h b/src/cryptonote_core/i_core_events.h
new file mode 100644
index 000000000..f49fbdf07
--- /dev/null
+++ b/src/cryptonote_core/i_core_events.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2019, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma once
+
+#include "cryptonote_basic/blobdatatype.h"
+#include "cryptonote_protocol/enums.h"
+#include "span.h"
+
+namespace cryptonote
+{
+ struct i_core_events
+ {
+ virtual ~i_core_events() noexcept
+ {}
+
+ virtual void on_transactions_relayed(epee::span<const cryptonote::blobdata> tx_blobs, relay_method tx_relay) = 0;
+ };
+}
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index 392e611e9..1bc475879 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -115,8 +115,10 @@ namespace cryptonote
}
//---------------------------------------------------------------------------------
- bool tx_memory_pool::add_tx(transaction &tx, /*const crypto::hash& tx_prefix_hash,*/ const crypto::hash &id, const cryptonote::blobdata &blob, size_t tx_weight, tx_verification_context& tvc, bool kept_by_block, bool relayed, bool do_not_relay, uint8_t version)
+ bool tx_memory_pool::add_tx(transaction &tx, /*const crypto::hash& tx_prefix_hash,*/ const crypto::hash &id, const cryptonote::blobdata &blob, size_t tx_weight, tx_verification_context& tvc, relay_method tx_relay, bool relayed, uint8_t version)
{
+ const bool kept_by_block = (tx_relay == relay_method::block);
+
// this should already be called with that lock, but let's make it explicit for clarity
CRITICAL_REGION_LOCAL(m_transactions_lock);
@@ -227,7 +229,7 @@ namespace cryptonote
crypto::hash max_used_block_id = null_hash;
uint64_t max_used_block_height = 0;
- cryptonote::txpool_tx_meta_t meta;
+ cryptonote::txpool_tx_meta_t meta{};
bool ch_inp_res = check_tx_inputs([&tx]()->cryptonote::transaction&{ return tx; }, id, max_used_block_height, max_used_block_id, tvc, kept_by_block);
if(!ch_inp_res)
{
@@ -241,11 +243,10 @@ namespace cryptonote
meta.max_used_block_height = 0;
meta.last_failed_height = 0;
meta.last_failed_id = null_hash;
- meta.kept_by_block = kept_by_block;
meta.receive_time = receive_time;
meta.last_relayed_time = time(NULL);
meta.relayed = relayed;
- meta.do_not_relay = do_not_relay;
+ meta.set_relay_method(tx_relay);
meta.double_spend_seen = have_tx_keyimges_as_spent(tx);
meta.pruned = tx.pruned;
meta.bf_padding = 0;
@@ -256,15 +257,16 @@ namespace cryptonote
m_parsed_tx_cache.insert(std::make_pair(id, tx));
CRITICAL_REGION_LOCAL1(m_blockchain);
LockedTXN lock(m_blockchain);
- m_blockchain.add_txpool_tx(id, blob, meta);
- if (!insert_key_images(tx, id, kept_by_block))
+ if (!insert_key_images(tx, id, tx_relay))
return false;
+
+ m_blockchain.add_txpool_tx(id, blob, meta);
m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)(tx_weight ? tx_weight : 1), receive_time), id);
lock.commit();
}
catch (const std::exception &e)
{
- MERROR("transaction already exists at inserting in memory pool: " << e.what());
+ MERROR("Error adding transaction to txpool: " << e.what());
return false;
}
tvc.m_verifivation_impossible = true;
@@ -280,7 +282,6 @@ namespace cryptonote
{
//update transactions container
meta.weight = tx_weight;
- meta.kept_by_block = kept_by_block;
meta.fee = fee;
meta.max_used_block_id = max_used_block_id;
meta.max_used_block_height = max_used_block_height;
@@ -289,7 +290,7 @@ namespace cryptonote
meta.receive_time = receive_time;
meta.last_relayed_time = time(NULL);
meta.relayed = relayed;
- meta.do_not_relay = do_not_relay;
+ meta.set_relay_method(tx_relay);
meta.double_spend_seen = false;
meta.pruned = tx.pruned;
meta.bf_padding = 0;
@@ -302,20 +303,21 @@ namespace cryptonote
CRITICAL_REGION_LOCAL1(m_blockchain);
LockedTXN lock(m_blockchain);
m_blockchain.remove_txpool_tx(id);
- m_blockchain.add_txpool_tx(id, blob, meta);
- if (!insert_key_images(tx, id, kept_by_block))
+ if (!insert_key_images(tx, id, tx_relay))
return false;
+
+ m_blockchain.add_txpool_tx(id, blob, meta);
m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)(tx_weight ? tx_weight : 1), receive_time), id);
lock.commit();
}
catch (const std::exception &e)
{
- MERROR("internal error: transaction already exists at inserting in memory pool: " << e.what());
+ MERROR("internal error: error adding transaction to txpool: " << e.what());
return false;
}
tvc.m_added_to_pool = true;
- if(meta.fee > 0 && !do_not_relay)
+ if(meta.fee > 0 && tx_relay != relay_method::none)
tvc.m_should_be_relayed = true;
}
@@ -331,7 +333,7 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------------------------
- bool tx_memory_pool::add_tx(transaction &tx, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay, uint8_t version)
+ bool tx_memory_pool::add_tx(transaction &tx, tx_verification_context& tvc, relay_method tx_relay, bool relayed, uint8_t version)
{
crypto::hash h = null_hash;
size_t blob_size = 0;
@@ -339,7 +341,7 @@ namespace cryptonote
t_serializable_object_to_blob(tx, bl);
if (bl.size() == 0 || !get_transaction_hash(tx, h))
return false;
- return add_tx(tx, h, bl, get_transaction_weight(tx, bl.size()), tvc, keeped_by_block, relayed, do_not_relay, version);
+ return add_tx(tx, h, bl, get_transaction_weight(tx, bl.size()), tvc, tx_relay, relayed, version);
}
//---------------------------------------------------------------------------------
size_t tx_memory_pool::get_txpool_weight() const
@@ -375,7 +377,7 @@ namespace cryptonote
txpool_tx_meta_t meta;
if (!m_blockchain.get_txpool_tx_meta(txid, meta))
{
- MERROR("Failed to find tx in txpool");
+ MERROR("Failed to find tx_meta in txpool");
return;
}
// don't prune the kept_by_block ones, they're likely added because we're adding a block with those
@@ -384,7 +386,7 @@ namespace cryptonote
--it;
continue;
}
- cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(txid);
+ cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(txid, relay_category::all);
cryptonote::transaction_prefix tx;
if (!parse_and_validate_tx_prefix_from_blob(txblob, tx))
{
@@ -413,17 +415,38 @@ namespace cryptonote
MINFO("Pool weight after pruning is larger than limit: " << m_txpool_weight << "/" << bytes);
}
//---------------------------------------------------------------------------------
- bool tx_memory_pool::insert_key_images(const transaction_prefix &tx, const crypto::hash &id, bool kept_by_block)
+ bool tx_memory_pool::insert_key_images(const transaction_prefix &tx, const crypto::hash &id, relay_method tx_relay)
{
for(const auto& in: tx.vin)
{
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, txin, false);
std::unordered_set<crypto::hash>& kei_image_set = m_spent_key_images[txin.k_image];
- CHECK_AND_ASSERT_MES(kept_by_block || kei_image_set.size() == 0, false, "internal error: kept_by_block=" << kept_by_block
- << ", kei_image_set.size()=" << kei_image_set.size() << ENDL << "txin.k_image=" << txin.k_image << ENDL
- << "tx_id=" << id );
- auto ins_res = kei_image_set.insert(id);
- CHECK_AND_ASSERT_MES(ins_res.second, false, "internal error: try to insert duplicate iterator in key_image set");
+
+ /* If any existing key-image in the set is publicly visible AND this is
+ not forcibly "kept_by_block", then fail (duplicate key image). If all
+ existing key images are supposed to be hidden, we silently allow so
+ that the node doesn't leak knowledge of a local/stem tx. */
+ bool visible = false;
+ if (tx_relay != relay_method::block)
+ {
+ for (const crypto::hash& other_id : kei_image_set)
+ visible |= m_blockchain.txpool_tx_matches_category(other_id, relay_category::legacy);
+ }
+
+ CHECK_AND_ASSERT_MES(!visible, false, "internal error: tx_relay=" << unsigned(tx_relay)
+ << ", kei_image_set.size()=" << kei_image_set.size() << ENDL << "txin.k_image=" << txin.k_image << ENDL
+ << "tx_id=" << id);
+
+ /* If adding a tx (hash) that already exists, fail only if the tx has
+ been publicly "broadcast" previously. This way, when a private tx is
+ received for the first time from a remote node, "this" node will
+ respond as-if it were seen for the first time. LMDB does the
+ "hard-check" on key-images, so the effect is overwriting the existing
+ tx_pool metadata and "first seen" time. */
+ const bool new_or_previously_private =
+ kei_image_set.insert(id).second ||
+ !m_blockchain.txpool_tx_matches_category(id, relay_category::legacy);
+ CHECK_AND_ASSERT_MES(new_or_previously_private, false, "internal error: try to insert duplicate iterator in key_image set");
}
++m_cookie;
return true;
@@ -475,10 +498,10 @@ namespace cryptonote
txpool_tx_meta_t meta;
if (!m_blockchain.get_txpool_tx_meta(id, meta))
{
- MERROR("Failed to find tx in txpool");
+ MERROR("Failed to find tx_meta in txpool");
return false;
}
- txblob = m_blockchain.get_txpool_tx_blob(id);
+ txblob = m_blockchain.get_txpool_tx_blob(id, relay_category::all);
auto ci = m_parsed_tx_cache.find(id);
if (ci != m_parsed_tx_cache.end())
{
@@ -533,7 +556,7 @@ namespace cryptonote
MERROR("Failed to find tx in txpool");
return false;
}
- cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(txid);
+ cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(txid, relay_category::all);
auto ci = m_parsed_tx_cache.find(txid);
if (ci != m_parsed_tx_cache.end())
{
@@ -611,7 +634,7 @@ namespace cryptonote
remove.push_back(std::make_pair(txid, meta.weight));
}
return true;
- }, false);
+ }, false, relay_category::all);
if (!remove.empty())
{
@@ -621,7 +644,7 @@ namespace cryptonote
const crypto::hash &txid = entry.first;
try
{
- cryptonote::blobdata bd = m_blockchain.get_txpool_tx_blob(txid);
+ cryptonote::blobdata bd = m_blockchain.get_txpool_tx_blob(txid, relay_category::all);
cryptonote::transaction_prefix tx;
if (!parse_and_validate_tx_prefix_from_blob(bd, tx))
{
@@ -649,7 +672,7 @@ namespace cryptonote
}
//---------------------------------------------------------------------------------
//TODO: investigate whether boolean return is appropriate
- bool tx_memory_pool::get_relayable_transactions(std::vector<std::pair<crypto::hash, cryptonote::blobdata>> &txs) const
+ bool tx_memory_pool::get_relayable_transactions(std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>> &txs) const
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
@@ -667,8 +690,7 @@ namespace cryptonote
{
try
{
- cryptonote::blobdata bd = m_blockchain.get_txpool_tx_blob(txid);
- txs.push_back(std::make_pair(txid, bd));
+ txs.emplace_back(txid, m_blockchain.get_txpool_tx_blob(txid, relay_category::all), meta.get_relay_method());
}
catch (const std::exception &e)
{
@@ -678,26 +700,27 @@ namespace cryptonote
}
}
return true;
- }, false);
+ }, false, relay_category::relayable);
return true;
}
//---------------------------------------------------------------------------------
- void tx_memory_pool::set_relayed(const std::vector<std::pair<crypto::hash, cryptonote::blobdata>> &txs)
+ void tx_memory_pool::set_relayed(const epee::span<const crypto::hash> hashes, const relay_method method)
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
const time_t now = time(NULL);
LockedTXN lock(m_blockchain);
- for (auto it = txs.begin(); it != txs.end(); ++it)
+ for (const auto& hash : hashes)
{
try
{
txpool_tx_meta_t meta;
- if (m_blockchain.get_txpool_tx_meta(it->first, meta))
+ if (m_blockchain.get_txpool_tx_meta(hash, meta))
{
meta.relayed = true;
meta.last_relayed_time = now;
- m_blockchain.update_txpool_tx(it->first, meta);
+ meta.set_relay_method(method);
+ m_blockchain.update_txpool_tx(hash, meta);
}
}
catch (const std::exception &e)
@@ -709,18 +732,19 @@ namespace cryptonote
lock.commit();
}
//---------------------------------------------------------------------------------
- size_t tx_memory_pool::get_transactions_count(bool include_unrelayed_txes) const
+ size_t tx_memory_pool::get_transactions_count(bool include_sensitive) const
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
- return m_blockchain.get_txpool_tx_count(include_unrelayed_txes);
+ return m_blockchain.get_txpool_tx_count(include_sensitive);
}
//---------------------------------------------------------------------------------
- void tx_memory_pool::get_transactions(std::vector<transaction>& txs, bool include_unrelayed_txes) const
+ void tx_memory_pool::get_transactions(std::vector<transaction>& txs, bool include_sensitive) const
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
- txs.reserve(m_blockchain.get_txpool_tx_count(include_unrelayed_txes));
+ const relay_category category = include_sensitive ? relay_category::all : relay_category::broadcasted;
+ txs.reserve(m_blockchain.get_txpool_tx_count(include_sensitive));
m_blockchain.for_all_txpool_txes([&txs](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
transaction tx;
if (!(meta.pruned ? parse_and_validate_tx_base_from_blob(*bd, tx) : parse_and_validate_tx_from_blob(*bd, tx)))
@@ -732,39 +756,42 @@ namespace cryptonote
tx.set_hash(txid);
txs.push_back(std::move(tx));
return true;
- }, true, include_unrelayed_txes);
+ }, true, category);
}
//------------------------------------------------------------------
- void tx_memory_pool::get_transaction_hashes(std::vector<crypto::hash>& txs, bool include_unrelayed_txes) const
+ void tx_memory_pool::get_transaction_hashes(std::vector<crypto::hash>& txs, bool include_sensitive) const
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
- txs.reserve(m_blockchain.get_txpool_tx_count(include_unrelayed_txes));
+ const relay_category category = include_sensitive ? relay_category::all : relay_category::broadcasted;
+ txs.reserve(m_blockchain.get_txpool_tx_count(include_sensitive));
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);
return true;
- }, false, include_unrelayed_txes);
+ }, false, category);
}
//------------------------------------------------------------------
- void tx_memory_pool::get_transaction_backlog(std::vector<tx_backlog_entry>& backlog, bool include_unrelayed_txes) const
+ void tx_memory_pool::get_transaction_backlog(std::vector<tx_backlog_entry>& backlog, bool include_sensitive) const
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
const uint64_t now = time(NULL);
- backlog.reserve(m_blockchain.get_txpool_tx_count(include_unrelayed_txes));
+ const relay_category category = include_sensitive ? relay_category::all : relay_category::broadcasted;
+ backlog.reserve(m_blockchain.get_txpool_tx_count(include_sensitive));
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.weight, meta.fee, meta.receive_time - now});
return true;
- }, false, include_unrelayed_txes);
+ }, false, category);
}
//------------------------------------------------------------------
- void tx_memory_pool::get_transaction_stats(struct txpool_stats& stats, bool include_unrelayed_txes) const
+ void tx_memory_pool::get_transaction_stats(struct txpool_stats& stats, bool include_sensitive) const
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
const uint64_t now = time(NULL);
+ const relay_category category = include_sensitive ? relay_category::all : relay_category::broadcasted;
std::map<uint64_t, txpool_histo> agebytes;
- stats.txs_total = m_blockchain.get_txpool_tx_count(include_unrelayed_txes);
+ stats.txs_total = m_blockchain.get_txpool_tx_count(include_sensitive);
std::vector<uint32_t> weights;
weights.reserve(stats.txs_total);
m_blockchain.for_all_txpool_txes([&stats, &weights, now, &agebytes](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
@@ -789,7 +816,8 @@ namespace cryptonote
if (meta.double_spend_seen)
++stats.num_double_spends;
return true;
- }, false, include_unrelayed_txes);
+ }, false, category);
+
stats.bytes_med = epee::misc_utils::median(weights);
if (stats.txs_total > 1)
{
@@ -847,8 +875,10 @@ namespace cryptonote
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
- tx_infos.reserve(m_blockchain.get_txpool_tx_count());
- key_image_infos.reserve(m_blockchain.get_txpool_tx_count());
+ const relay_category category = include_sensitive_data ? relay_category::all : relay_category::broadcasted;
+ const size_t count = m_blockchain.get_txpool_tx_count(include_sensitive_data);
+ tx_infos.reserve(count);
+ key_image_infos.reserve(count);
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;
txi.id_hash = epee::string_tools::pod_to_hex(txid);
@@ -879,7 +909,7 @@ namespace cryptonote
txi.double_spend_seen = meta.double_spend_seen;
tx_infos.push_back(std::move(txi));
return true;
- }, true, include_sensitive_data);
+ }, true, category);
txpool_tx_meta_t meta;
for (const key_images_container::value_type& kee : m_spent_key_images) {
@@ -889,30 +919,13 @@ namespace cryptonote
ki.id_hash = epee::string_tools::pod_to_hex(k_image);
for (const crypto::hash& tx_id_hash : kei_image_set)
{
- if (!include_sensitive_data)
- {
- try
- {
- if (!m_blockchain.get_txpool_tx_meta(tx_id_hash, meta))
- {
- MERROR("Failed to get tx meta from txpool");
- return false;
- }
- 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));
+ if (m_blockchain.txpool_tx_matches_category(tx_id_hash, category))
+ ki.txs_hashes.push_back(epee::string_tools::pod_to_hex(tx_id_hash));
}
+
// 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);
+ key_image_infos.push_back(std::move(ki));
}
return true;
}
@@ -948,18 +961,19 @@ namespace cryptonote
txi.double_spend_seen = meta.double_spend_seen;
tx_infos.push_back(txi);
return true;
- }, true, false);
+ }, true, relay_category::broadcasted);
for (const key_images_container::value_type& kee : m_spent_key_images) {
std::vector<crypto::hash> tx_hashes;
const std::unordered_set<crypto::hash>& kei_image_set = kee.second;
for (const crypto::hash& tx_id_hash : kei_image_set)
{
- tx_hashes.push_back(tx_id_hash);
+ if (m_blockchain.txpool_tx_matches_category(tx_id_hash, relay_category::broadcasted))
+ tx_hashes.push_back(tx_id_hash);
}
- const crypto::key_image& k_image = kee.first;
- key_image_infos[k_image] = std::move(tx_hashes);
+ if (!tx_hashes.empty())
+ key_image_infos[kee.first] = std::move(tx_hashes);
}
return true;
}
@@ -973,19 +987,26 @@ namespace cryptonote
for (const auto& image : key_images)
{
- spent.push_back(m_spent_key_images.find(image) == m_spent_key_images.end() ? false : true);
+ bool is_spent = false;
+ const auto found = m_spent_key_images.find(image);
+ if (found != m_spent_key_images.end())
+ {
+ for (const crypto::hash& tx_hash : found->second)
+ is_spent |= m_blockchain.txpool_tx_matches_category(tx_hash, relay_category::broadcasted);
+ }
+ spent.push_back(is_spent);
}
return true;
}
//---------------------------------------------------------------------------------
- bool tx_memory_pool::get_transaction(const crypto::hash& id, cryptonote::blobdata& txblob) const
+ bool tx_memory_pool::get_transaction(const crypto::hash& id, cryptonote::blobdata& txblob, relay_category tx_category) const
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
try
{
- return m_blockchain.get_txpool_tx_blob(id, txblob);
+ return m_blockchain.get_txpool_tx_blob(id, txblob, tx_category);
}
catch (const std::exception &e)
{
@@ -1009,11 +1030,11 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------------------------
- bool tx_memory_pool::have_tx(const crypto::hash &id) const
+ bool tx_memory_pool::have_tx(const crypto::hash &id, relay_category tx_category) const
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
- return m_blockchain.get_db().txpool_has_tx(id);
+ return m_blockchain.get_db().txpool_has_tx(id, tx_category);
}
//---------------------------------------------------------------------------------
bool tx_memory_pool::have_tx_keyimges_as_spent(const transaction& tx) const
@@ -1032,7 +1053,14 @@ namespace cryptonote
bool tx_memory_pool::have_tx_keyimg_as_spent(const crypto::key_image& key_im) const
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
- return m_spent_key_images.end() != m_spent_key_images.find(key_im);
+ bool spent = false;
+ const auto found = m_spent_key_images.find(key_im);
+ if (found != m_spent_key_images.end())
+ {
+ for (const crypto::hash& tx_hash : found->second)
+ spent |= m_blockchain.txpool_tx_matches_category(tx_hash, relay_category::broadcasted);
+ }
+ return spent;
}
//---------------------------------------------------------------------------------
void tx_memory_pool::lock() const
@@ -1217,13 +1245,14 @@ namespace cryptonote
<< "weight: " << meta.weight << std::endl
<< "fee: " << print_money(meta.fee) << std::endl
<< "kept_by_block: " << (meta.kept_by_block ? 'T' : 'F') << std::endl
+ << "is_local" << (meta.is_local ? 'T' : 'F') << std::endl
<< "double_spend_seen: " << (meta.double_spend_seen ? 'T' : 'F') << std::endl
<< "max_used_block_height: " << meta.max_used_block_height << std::endl
<< "max_used_block_id: " << meta.max_used_block_id << std::endl
<< "last_failed_height: " << meta.last_failed_height << std::endl
<< "last_failed_id: " << meta.last_failed_id << std::endl;
return true;
- }, !short_format);
+ }, !short_format, relay_category::all);
return ss.str();
}
@@ -1255,7 +1284,7 @@ namespace cryptonote
for (; sorted_it != m_txs_by_fee_and_receive_time.end(); ++sorted_it)
{
txpool_tx_meta_t meta;
- if (!m_blockchain.get_txpool_tx_meta(sorted_it->second, meta))
+ if (!m_blockchain.get_txpool_tx_meta(sorted_it->second, meta) && !meta.matches(relay_category::legacy))
{
MERROR(" failed to find tx meta");
continue;
@@ -1304,7 +1333,9 @@ namespace cryptonote
}
}
- cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(sorted_it->second);
+ // "local" and "stem" txes are filtered above
+ cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(sorted_it->second, relay_category::all);
+
cryptonote::transaction tx;
// Skip transactions that are not ready to be
@@ -1379,7 +1410,7 @@ namespace cryptonote
remove.insert(txid);
}
return true;
- }, false);
+ }, false, relay_category::all);
size_t n_removed = 0;
if (!remove.empty())
@@ -1389,7 +1420,7 @@ namespace cryptonote
{
try
{
- cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(txid);
+ cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(txid, relay_category::all);
cryptonote::transaction tx;
if (!parse_and_validate_tx_from_blob(txblob, tx)) // remove pruned ones on startup, they're meant to be temporary
{
@@ -1450,7 +1481,7 @@ namespace cryptonote
remove.push_back(txid);
return true;
}
- if (!insert_key_images(tx, txid, meta.kept_by_block))
+ if (!insert_key_images(tx, txid, meta.get_relay_method()))
{
MFATAL("Failed to insert key images from txpool tx");
return false;
@@ -1458,7 +1489,7 @@ namespace cryptonote
m_txs_by_fee_and_receive_time.emplace(std::pair<double, time_t>(meta.fee / (double)meta.weight, meta.receive_time), txid);
m_txpool_weight += meta.weight;
return true;
- }, true);
+ }, true, relay_category::all);
if (!r)
return false;
}
diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h
index dec7e3cd9..f716440ad 100644
--- a/src/cryptonote_core/tx_pool.h
+++ b/src/cryptonote_core/tx_pool.h
@@ -32,17 +32,20 @@
#include "include_base_utils.h"
#include <set>
+#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <queue>
#include <boost/serialization/version.hpp>
#include <boost/utility.hpp>
+#include "span.h"
#include "string_tools.h"
#include "syncobj.h"
#include "math_helper.h"
#include "cryptonote_basic/cryptonote_basic_impl.h"
#include "cryptonote_basic/verification_context.h"
+#include "cryptonote_protocol/enums.h"
#include "blockchain_db/blockchain_db.h"
#include "crypto/hash.h"
#include "rpc/core_rpc_server_commands_defs.h"
@@ -105,9 +108,10 @@ namespace cryptonote
* @copydoc add_tx(transaction&, tx_verification_context&, bool, bool, uint8_t)
*
* @param id the transaction's hash
+ * @tx_relay how the transaction was received
* @param tx_weight the transaction's weight
*/
- bool add_tx(transaction &tx, const crypto::hash &id, const cryptonote::blobdata &blob, size_t tx_weight, tx_verification_context& tvc, bool kept_by_block, bool relayed, bool do_not_relay, uint8_t version);
+ bool add_tx(transaction &tx, const crypto::hash &id, const cryptonote::blobdata &blob, size_t tx_weight, tx_verification_context& tvc, relay_method tx_relay, bool relayed, uint8_t version);
/**
* @brief add a transaction to the transaction pool
@@ -119,14 +123,13 @@ namespace cryptonote
*
* @param tx the transaction to be added
* @param tvc return-by-reference status about the transaction verification
- * @param kept_by_block has this transaction been in a block?
+ * @tx_relay how the transaction was received
* @param relayed was this transaction from the network or a local client?
- * @param do_not_relay to avoid relaying the transaction to the network
* @param version the version used to create the transaction
*
* @return true if the transaction passes validations, otherwise false
*/
- bool add_tx(transaction &tx, tx_verification_context& tvc, bool kept_by_block, bool relayed, bool do_not_relay, uint8_t version);
+ bool add_tx(transaction &tx, tx_verification_context& tvc, relay_method tx_relay, bool relayed, uint8_t version);
/**
* @brief takes a transaction with the given hash from the pool
@@ -149,10 +152,11 @@ namespace cryptonote
* @brief checks if the pool has a transaction with the given hash
*
* @param id the hash to look for
+ * @param tx_category a filter for txes
*
- * @return true if the transaction is in the pool, otherwise false
+ * @return true if the transaction is in the pool and meets tx_category requirements
*/
- bool have_tx(const crypto::hash &id) const;
+ bool have_tx(const crypto::hash &id, relay_category tx_category) const;
/**
* @brief action to take when notified of a block added to the blockchain
@@ -236,37 +240,37 @@ namespace cryptonote
* @brief get a list of all transactions in the pool
*
* @param txs return-by-reference the list of transactions
- * @param include_unrelayed_txes include unrelayed txes in the result
+ * @param include_sensitive return stempool, anonymity-pool, and unrelayed txes
*
*/
- void get_transactions(std::vector<transaction>& txs, bool include_unrelayed_txes = true) const;
+ void get_transactions(std::vector<transaction>& txs, bool include_sensitive = false) const;
/**
* @brief get a list of all transaction hashes in the pool
*
* @param txs return-by-reference the list of transactions
- * @param include_unrelayed_txes include unrelayed txes in the result
+ * @param include_sensitive return stempool, anonymity-pool, and unrelayed txes
*
*/
- void get_transaction_hashes(std::vector<crypto::hash>& txs, bool include_unrelayed_txes = true) const;
+ void get_transaction_hashes(std::vector<crypto::hash>& txs, bool include_sensitive = false) const;
/**
* @brief get (weight, fee, receive time) for all transaction in the pool
*
* @param txs return-by-reference that data
- * @param include_unrelayed_txes include unrelayed txes in the result
+ * @param include_sensitive return stempool, anonymity-pool, and unrelayed txes
*
*/
- void get_transaction_backlog(std::vector<tx_backlog_entry>& backlog, bool include_unrelayed_txes = true) const;
+ void get_transaction_backlog(std::vector<tx_backlog_entry>& backlog, bool include_sensitive = false) const;
/**
* @brief get a summary statistics of all transaction hashes in the pool
*
* @param stats return-by-reference the pool statistics
- * @param include_unrelayed_txes include unrelayed txes in the result
+ * @param include_sensitive return stempool, anonymity-pool, and unrelayed txes
*
*/
- void get_transaction_stats(struct txpool_stats& stats, bool include_unrelayed_txes = true) const;
+ void get_transaction_stats(struct txpool_stats& stats, bool include_sensitive = false) const;
/**
* @brief get information about all transactions and key images in the pool
@@ -275,11 +279,12 @@ namespace cryptonote
*
* @param tx_infos return-by-reference the transactions' 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
+ * @param include_sensitive_data return stempool, anonymity-pool, and unrelayed
+ * txes and fields that are sensitive to the node privacy
*
* @return true
*/
- 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;
+ 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 = false) const;
/**
* @brief get information about all transactions and key images in the pool
@@ -308,10 +313,11 @@ namespace cryptonote
*
* @param h the hash of the transaction to get
* @param tx return-by-reference the transaction blob requested
+ * @param tx_relay last relay method us
*
* @return true if the transaction is found, otherwise false
*/
- bool get_transaction(const crypto::hash& h, cryptonote::blobdata& txblob) const;
+ bool get_transaction(const crypto::hash& h, cryptonote::blobdata& txblob, relay_category tx_category) const;
/**
* @brief get a list of all relayable transactions and their hashes
@@ -326,21 +332,22 @@ namespace cryptonote
*
* @return true
*/
- bool get_relayable_transactions(std::vector<std::pair<crypto::hash, cryptonote::blobdata>>& txs) const;
+ bool get_relayable_transactions(std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>>& txs) const;
/**
* @brief tell the pool that certain transactions were just relayed
*
- * @param txs the list of transactions (and their hashes)
+ * @param hashes list of tx hashes that are about to be relayed
+ * @param tx_relay update how the tx left this node
*/
- void set_relayed(const std::vector<std::pair<crypto::hash, cryptonote::blobdata>>& txs);
+ void set_relayed(epee::span<const crypto::hash> hashes, relay_method tx_relay);
/**
* @brief get the total number of transactions in the pool
*
* @return the number of transactions in the pool
*/
- size_t get_transactions_count(bool include_unrelayed_txes = true) const;
+ size_t get_transactions_count(bool include_sensitive = false) const;
/**
* @brief get a string containing human-readable pool information
@@ -441,7 +448,7 @@ namespace cryptonote
*
* @return true on success, false on error
*/
- bool insert_key_images(const transaction_prefix &tx, const crypto::hash &txid, bool kept_by_block);
+ bool insert_key_images(const transaction_prefix &tx, const crypto::hash &txid, relay_method tx_relay);
/**
* @brief remove old transactions from the pool
@@ -544,7 +551,7 @@ namespace cryptonote
* transaction on the assumption that the original will not be in a
* block again.
*/
- typedef std::unordered_map<crypto::key_image, std::unordered_set<crypto::hash> > key_images_container;
+ typedef std::unordered_map<crypto::key_image, std::unordered_set<crypto::hash>> key_images_container;
#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
public:
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h
index 3b456e324..ddbd45a61 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h
@@ -130,7 +130,7 @@ namespace cryptonote
//----------------- i_bc_protocol_layout ---------------------------------------
virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context);
- virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context);
+ virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, const boost::uuids::uuid& source, epee::net_utils::zone zone);
//----------------------------------------------------------------------------------
//bool get_payload_sync_data(HANDSHAKE_DATA::request& hshd, cryptonote_connection_context& context);
bool should_drop_connection(cryptonote_connection_context& context, uint32_t next_stripe);
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 74ceeb41d..e20934a25 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -455,7 +455,7 @@ namespace cryptonote
for(auto tx_blob_it = arg.b.txs.begin(); tx_blob_it!=arg.b.txs.end();tx_blob_it++)
{
cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
- m_core.handle_incoming_tx(*tx_blob_it, tvc, true, true, false);
+ m_core.handle_incoming_tx(*tx_blob_it, tvc, relay_method::block, true);
if(tvc.m_verifivation_failed)
{
LOG_PRINT_CCONTEXT_L1("Block verification failed: transaction verification failed, dropping connection");
@@ -619,7 +619,7 @@ namespace cryptonote
{
MDEBUG("Incoming tx " << tx_hash << " not in pool, adding");
cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
- if(!m_core.handle_incoming_tx(tx_blob, tvc, true, true, false) || tvc.m_verifivation_failed)
+ if(!m_core.handle_incoming_tx(tx_blob, tvc, relay_method::block, true) || tvc.m_verifivation_failed)
{
LOG_PRINT_CCONTEXT_L1("Block verification failed: transaction verification failed, dropping connection");
drop_connection(context, false, false);
@@ -667,13 +667,13 @@ namespace cryptonote
drop_connection(context, false, false);
m_core.resume_mine();
return 1;
- }
-
+ }
+
size_t tx_idx = 0;
for(auto& tx_hash: new_block.tx_hashes)
{
cryptonote::blobdata txblob;
- if(m_core.get_pool_transaction(tx_hash, txblob))
+ if(m_core.get_pool_transaction(tx_hash, txblob, relay_category::broadcasted))
{
have_tx.push_back({txblob, crypto::null_hash});
}
@@ -702,7 +702,7 @@ namespace cryptonote
need_tx_indices.push_back(tx_idx);
}
}
-
+
++tx_idx;
}
@@ -909,8 +909,8 @@ namespace cryptonote
newtxs.reserve(arg.txs.size());
for (size_t i = 0; i < arg.txs.size(); ++i)
{
- cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
- m_core.handle_incoming_tx({arg.txs[i], crypto::null_hash}, tvc, false, true, false);
+ cryptonote::tx_verification_context tvc{};
+ m_core.handle_incoming_tx({arg.txs[i], crypto::null_hash}, tvc, relay_method::flood, true);
if(tvc.m_verifivation_failed)
{
LOG_PRINT_CCONTEXT_L1("Tx verification failed, dropping connection");
@@ -925,7 +925,7 @@ namespace cryptonote
if(arg.txs.size())
{
//TODO: add announce usage here
- relay_transactions(arg, context);
+ relay_transactions(arg, context.m_connection_id, context.m_remote_address.get_zone());
}
return 1;
@@ -1316,7 +1316,7 @@ namespace cryptonote
TIME_MEASURE_START(transactions_process_time);
num_txs += block_entry.txs.size();
std::vector<tx_verification_context> tvc;
- m_core.handle_incoming_txs(block_entry.txs, tvc, true, true, false);
+ m_core.handle_incoming_txs(block_entry.txs, tvc, relay_method::block, true);
if (tvc.size() != block_entry.txs.size())
{
LOG_ERROR_CCONTEXT("Internal error: tvc.size() != block_entry.txs.size()");
@@ -2344,14 +2344,14 @@ skip:
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
- bool t_cryptonote_protocol_handler<t_core>::relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context)
+ bool t_cryptonote_protocol_handler<t_core>::relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, const boost::uuids::uuid& source, epee::net_utils::zone zone)
{
- for(auto& tx_blob : arg.txs)
- m_core.on_transaction_relayed(tx_blob);
-
- // no check for success, so tell core they're relayed unconditionally
- m_p2p->send_txs(std::move(arg.txs), exclude_context.m_remote_address.get_zone(), exclude_context.m_connection_id, m_core.pad_transactions());
- return true;
+ /* Push all outgoing transactions to this function. The behavior needs to
+ identify how the transaction is going to be relayed, and then update the
+ local mempool before doing the relay. The code was already updating the
+ DB twice on received transactions - it is difficult to workaround this
+ due to the internal design. */
+ return m_p2p->send_txs(std::move(arg.txs), zone, source, m_core, m_core.pad_transactions()) != epee::net_utils::zone::invalid;
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler_common.h b/src/cryptonote_protocol/cryptonote_protocol_handler_common.h
index a67178c52..978a9ebf3 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler_common.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler_common.h
@@ -41,7 +41,7 @@ namespace cryptonote
struct i_cryptonote_protocol
{
virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context)=0;
- virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context)=0;
+ virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, const boost::uuids::uuid& source, epee::net_utils::zone zone)=0;
//virtual bool request_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote_connection_context& context)=0;
};
@@ -54,7 +54,7 @@ namespace cryptonote
{
return false;
}
- virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context)
+ virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, const boost::uuids::uuid& source, epee::net_utils::zone zone)
{
return false;
}
diff --git a/src/cryptonote_protocol/enums.h b/src/cryptonote_protocol/enums.h
new file mode 100644
index 000000000..ad4eedf4c
--- /dev/null
+++ b/src/cryptonote_protocol/enums.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2019, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma once
+
+#include <cstdint>
+
+namespace cryptonote
+{
+ //! Methods tracking how a tx was received and relayed
+ enum class relay_method : std::uint8_t
+ {
+ none = 0, //!< Received via RPC with `do_not_relay` set
+ local, //!< Received via RPC; trying to send over i2p/tor, etc.
+ block, //!< Received in block, takes precedence over others
+ flood //!< Received/sent over public networks
+ };
+}
diff --git a/src/cryptonote_protocol/fwd.h b/src/cryptonote_protocol/fwd.h
new file mode 100644
index 000000000..616b48be3
--- /dev/null
+++ b/src/cryptonote_protocol/fwd.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2019, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma once
+
+namespace cryptonote
+{
+ class core;
+ struct cryptonote_connection_context;
+ struct i_core_events;
+}
+
diff --git a/src/cryptonote_protocol/levin_notify.h b/src/cryptonote_protocol/levin_notify.h
index 484243af5..8bc9b72fa 100644
--- a/src/cryptonote_protocol/levin_notify.h
+++ b/src/cryptonote_protocol/levin_notify.h
@@ -35,6 +35,7 @@
#include "byte_slice.h"
#include "cryptonote_basic/blobdatatype.h"
+#include "cryptonote_protocol/fwd.h"
#include "net/enums.h"
#include "span.h"
@@ -53,11 +54,6 @@ namespace nodetool
namespace cryptonote
{
- struct cryptonote_connection_context;
-}
-
-namespace cryptonote
-{
namespace levin
{
namespace detail
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index b827221f6..99a460c78 100644
--- a/src/daemon/command_parser_executor.cpp
+++ b/src/daemon/command_parser_executor.cpp
@@ -28,7 +28,6 @@
#include "common/dns_utils.h"
#include "common/command_line.h"
-#include "version.h"
#include "daemon/command_parser_executor.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
@@ -803,8 +802,7 @@ bool t_command_parser_executor::rpc_payments(const std::vector<std::string>& arg
bool t_command_parser_executor::version(const std::vector<std::string>& args)
{
- std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << std::endl;
- return true;
+ return m_executor.version();
}
bool t_command_parser_executor::prune_blockchain(const std::vector<std::string>& args)
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index ed614a89b..ef9fed177 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -38,6 +38,7 @@
#include "cryptonote_basic/difficulty.h"
#include "cryptonote_basic/hardfork.h"
#include "rpc/rpc_payment_signature.h"
+#include "rpc/rpc_version_str.h"
#include <boost/format.hpp>
#include <ctime>
#include <string>
@@ -380,7 +381,7 @@ static void get_metric_prefix(cryptonote::difficulty_type hr, double& hr_d, char
prefix = 0;
return;
}
- static const char metric_prefixes[4] = { 'k', 'M', 'G', 'T' };
+ static const char metric_prefixes[] = { 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' };
for (size_t i = 0; i < sizeof(metric_prefixes); ++i)
{
if (hr < 1000000)
@@ -2442,4 +2443,39 @@ bool t_rpc_command_executor::rpc_payments()
return true;
}
+bool t_rpc_command_executor::version()
+{
+ cryptonote::COMMAND_RPC_GET_INFO::request req;
+ cryptonote::COMMAND_RPC_GET_INFO::response res;
+
+ const char *fail_message = "Problem fetching info";
+
+ if (m_is_rpc)
+ {
+ if (!m_rpc_client->rpc_request(req, res, "/getinfo", fail_message))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (!m_rpc_server->on_get_info(req, res) || res.status != CORE_RPC_STATUS_OK)
+ {
+ tools::fail_msg_writer() << make_error(fail_message, res.status);
+ return true;
+ }
+ }
+
+ if (res.version.empty() || !cryptonote::rpc::is_version_string_valid(res.version))
+ {
+ tools::fail_msg_writer() << "The daemon software version is not available.";
+ }
+ else
+ {
+ tools::success_msg_writer() << res.version;
+ }
+
+ return true;
+}
+
}// namespace daemonize
diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h
index e8b12cb9b..af55f0e22 100644
--- a/src/daemon/rpc_command_executor.h
+++ b/src/daemon/rpc_command_executor.h
@@ -163,6 +163,8 @@ public:
bool print_net_stats();
+ bool version();
+
bool set_bootstrap_daemon(
const std::string &address,
const std::string &username,
diff --git a/src/daemonizer/posix_fork.cpp b/src/daemonizer/posix_fork.cpp
index 5af4e1a4a..16758215d 100644
--- a/src/daemonizer/posix_fork.cpp
+++ b/src/daemonizer/posix_fork.cpp
@@ -127,13 +127,18 @@ void fork(const std::string & pidfile)
{
quit("Unable to open output file: " + output);
}
+#else
+ if (open("/dev/null", O_WRONLY) < 0)
+ {
+ quit("Unable to open /dev/null");
+ }
+#endif
// Also send standard error to the same log file.
if (dup(1) < 0)
{
quit("Unable to dup output descriptor");
}
-#endif
}
} // namespace posix
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index 8d861ce29..ee70c2806 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -43,6 +43,7 @@
#include <vector>
#include "cryptonote_config.h"
+#include "cryptonote_protocol/fwd.h"
#include "cryptonote_protocol/levin_notify.h"
#include "warnings.h"
#include "net/abstract_tcp_server2.h"
@@ -336,7 +337,7 @@ namespace nodetool
virtual void callback(p2p_connection_context& context);
//----------------- i_p2p_endpoint -------------------------------------------------------------
virtual bool relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> connections);
- virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, const bool pad_txs);
+ virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::i_core_events& core, bool pad_txs);
virtual bool invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context);
virtual bool invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context);
virtual bool drop_connection(const epee::net_utils::connection_context_base& context);
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index f8094bfa8..82abee71b 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -1882,6 +1882,7 @@ namespace nodetool
--i;
continue;
}
+ local_peerlist[i].last_seen = 0;
#ifdef CRYPTONOTE_PRUNING_DEBUG_SPOOF_SEED
be.pruning_seed = tools::make_pruning_seed(1 + (be.adr.as<epee::net_utils::ipv4_network_address>().ip()) % (1ul << CRYPTONOTE_PRUNING_LOG_STRIPES), CRYPTONOTE_PRUNING_LOG_STRIPES);
@@ -2053,13 +2054,18 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- epee::net_utils::zone node_server<t_payload_net_handler>::send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, const bool pad_txs)
+ epee::net_utils::zone node_server<t_payload_net_handler>::send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::i_core_events& core, const bool pad_txs)
{
namespace enet = epee::net_utils;
- const auto send = [&txs, &source, pad_txs] (std::pair<const enet::zone, network_zone>& network)
+ const auto send = [&txs, &source, &core, pad_txs] (std::pair<const enet::zone, network_zone>& network)
{
- if (network.second.m_notifier.send_txs(std::move(txs), source, (pad_txs || network.first != enet::zone::public_)))
+ const bool is_public = (network.first == enet::zone::public_);
+ const cryptonote::relay_method tx_relay = is_public ?
+ cryptonote::relay_method::flood : cryptonote::relay_method::local;
+
+ core.on_transactions_relayed(epee::to_span(txs), tx_relay);
+ if (network.second.m_notifier.send_txs(std::move(txs), source, (pad_txs || !is_public)))
return network.first;
return enet::zone::invalid;
};
diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h
index 752873666..aa1b83b83 100644
--- a/src/p2p/net_node_common.h
+++ b/src/p2p/net_node_common.h
@@ -34,6 +34,8 @@
#include <utility>
#include <vector>
#include "cryptonote_basic/blobdatatype.h"
+#include "cryptonote_protocol/enums.h"
+#include "cryptonote_protocol/fwd.h"
#include "net/enums.h"
#include "net/net_utils_base.h"
#include "p2p_protocol_defs.h"
@@ -48,7 +50,7 @@ namespace nodetool
struct i_p2p_endpoint
{
virtual bool relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> connections)=0;
- virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, const bool pad_txs)=0;
+ virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::i_core_events& core, bool pad_txs)=0;
virtual bool invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)=0;
virtual bool invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context)=0;
virtual bool drop_connection(const epee::net_utils::connection_context_base& context)=0;
@@ -73,7 +75,7 @@ namespace nodetool
{
return false;
}
- virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, const bool pad_txs)
+ virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::i_core_events& core, const bool pad_txs)
{
return epee::net_utils::zone::invalid;
}
diff --git a/src/ringct/bulletproofs.cc b/src/ringct/bulletproofs.cc
index ff6fee95c..80ecc5593 100644
--- a/src/ringct/bulletproofs.cc
+++ b/src/ringct/bulletproofs.cc
@@ -27,6 +27,7 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Adapted from Java code by Sarang Noether
+// Paper references are to https://eprint.iacr.org/2017/1066 (revision 1 July 2018)
#include <stdlib.h>
#include <boost/thread/mutex.hpp>
@@ -521,6 +522,7 @@ Bulletproof bulletproof_PROVE(const rct::keyV &sv, const rct::keyV &gamma)
}
PERF_TIMER_STOP_BP(PROVE_v);
+ // PAPER LINES 41-42
PERF_TIMER_START_BP(PROVE_aLaR);
for (size_t j = 0; j < M; ++j)
{
@@ -566,14 +568,14 @@ try_again:
rct::key hash_cache = rct::hash_to_scalar(V);
PERF_TIMER_START_BP(PROVE_step1);
- // PAPER LINES 38-39
+ // PAPER LINES 43-44
rct::key alpha = rct::skGen();
rct::key ve = vector_exponent(aL8, aR8);
rct::key A;
sc_mul(tmp.bytes, alpha.bytes, INV_EIGHT.bytes);
rct::addKeys(A, ve, rct::scalarmultBase(tmp));
- // PAPER LINES 40-42
+ // PAPER LINES 45-47
rct::keyV sL = rct::skvGen(MN), sR = rct::skvGen(MN);
rct::key rho = rct::skGen();
ve = vector_exponent(sL, sR);
@@ -581,7 +583,7 @@ try_again:
rct::addKeys(S, ve, rct::scalarmultBase(rho));
S = rct::scalarmultKey(S, INV_EIGHT);
- // PAPER LINES 43-45
+ // PAPER LINES 48-50
rct::key y = hash_cache_mash(hash_cache, A, S);
if (y == rct::zero())
{
@@ -598,24 +600,20 @@ try_again:
}
// Polynomial construction by coefficients
+ // PAPER LINES 70-71
rct::keyV l0 = vector_subtract(aL, z);
const rct::keyV &l1 = sL;
- // This computes the ugly sum/concatenation from PAPER LINE 65
rct::keyV zero_twos(MN);
const rct::keyV zpow = vector_powers(z, M+2);
- for (size_t i = 0; i < MN; ++i)
+ for (size_t j = 0; j < M; ++j)
{
- zero_twos[i] = rct::zero();
- for (size_t j = 1; j <= M; ++j)
- {
- if (i >= (j-1)*N && i < j*N)
+ for (size_t i = 0; i < N; ++i)
{
- CHECK_AND_ASSERT_THROW_MES(1+j < zpow.size(), "invalid zpow index");
- CHECK_AND_ASSERT_THROW_MES(i-(j-1)*N < twoN.size(), "invalid twoN index");
- sc_muladd(zero_twos[i].bytes, zpow[1+j].bytes, twoN[i-(j-1)*N].bytes, zero_twos[i].bytes);
+ CHECK_AND_ASSERT_THROW_MES(j+2 < zpow.size(), "invalid zpow index");
+ CHECK_AND_ASSERT_THROW_MES(i < twoN.size(), "invalid twoN index");
+ sc_mul(zero_twos[j*N+i].bytes,zpow[j+2].bytes,twoN[i].bytes);
}
- }
}
rct::keyV r0 = vector_add(aR, z);
@@ -624,7 +622,7 @@ try_again:
r0 = vector_add(r0, zero_twos);
rct::keyV r1 = hadamard(yMN, sR);
- // Polynomial construction before PAPER LINE 46
+ // Polynomial construction before PAPER LINE 51
rct::key t1_1 = inner_product(l0, r1);
rct::key t1_2 = inner_product(l1, r0);
rct::key t1;
@@ -634,7 +632,7 @@ try_again:
PERF_TIMER_STOP_BP(PROVE_step1);
PERF_TIMER_START_BP(PROVE_step2);
- // PAPER LINES 47-48
+ // PAPER LINES 52-53
rct::key tau1 = rct::skGen(), tau2 = rct::skGen();
rct::key T1, T2;
@@ -648,7 +646,7 @@ try_again:
ge_double_scalarmult_base_vartime_p3(&p3, tmp.bytes, &ge_p3_H, tmp2.bytes);
ge_p3_tobytes(T2.bytes, &p3);
- // PAPER LINES 49-51
+ // PAPER LINES 54-56
rct::key x = hash_cache_mash(hash_cache, z, T1, T2);
if (x == rct::zero())
{
@@ -657,7 +655,7 @@ try_again:
goto try_again;
}
- // PAPER LINES 52-53
+ // PAPER LINES 61-63
rct::key taux;
sc_mul(taux.bytes, tau1.bytes, x.bytes);
rct::key xsq;
@@ -671,7 +669,7 @@ try_again:
rct::key mu;
sc_muladd(mu.bytes, x.bytes, rho.bytes, alpha.bytes);
- // PAPER LINES 54-57
+ // PAPER LINES 58-60
rct::keyV l = l0;
l = vector_add(l, vector_scalar(l1, x));
rct::keyV r = r0;
@@ -690,7 +688,7 @@ try_again:
CHECK_AND_ASSERT_THROW_MES(test_t == t, "test_t check failed");
#endif
- // PAPER LINES 32-33
+ // PAPER LINE 6
rct::key x_ip = hash_cache_mash(hash_cache, x, taux, mu, t);
if (x_ip == rct::zero())
{
@@ -725,20 +723,19 @@ try_again:
PERF_TIMER_STOP_BP(PROVE_step3);
PERF_TIMER_START_BP(PROVE_step4);
- // PAPER LINE 13
const rct::keyV *scale = &yinvpow;
while (nprime > 1)
{
- // PAPER LINE 15
+ // PAPER LINE 20
nprime /= 2;
- // PAPER LINES 16-17
+ // PAPER LINES 21-22
PERF_TIMER_START_BP(PROVE_inner_product);
rct::key cL = inner_product(slice(aprime, 0, nprime), slice(bprime, nprime, bprime.size()));
rct::key cR = inner_product(slice(aprime, nprime, aprime.size()), slice(bprime, 0, nprime));
PERF_TIMER_STOP_BP(PROVE_inner_product);
- // PAPER LINES 18-19
+ // PAPER LINES 23-24
PERF_TIMER_START_BP(PROVE_LR);
sc_mul(tmp.bytes, cL.bytes, x_ip.bytes);
L[round] = cross_vector_exponent8(nprime, Gprime, nprime, Hprime, 0, aprime, 0, bprime, nprime, scale, &ge_p3_H, &tmp);
@@ -746,7 +743,7 @@ try_again:
R[round] = cross_vector_exponent8(nprime, Gprime, 0, Hprime, nprime, aprime, nprime, bprime, 0, scale, &ge_p3_H, &tmp);
PERF_TIMER_STOP_BP(PROVE_LR);
- // PAPER LINES 21-22
+ // PAPER LINES 25-27
w[round] = hash_cache_mash(hash_cache, L[round], R[round]);
if (w[round] == rct::zero())
{
@@ -755,7 +752,7 @@ try_again:
goto try_again;
}
- // PAPER LINES 24-25
+ // PAPER LINES 29-30
const rct::key winv = invert(w[round]);
if (nprime > 1)
{
@@ -765,7 +762,7 @@ try_again:
PERF_TIMER_STOP_BP(PROVE_hadamard2);
}
- // PAPER LINES 28-29
+ // PAPER LINES 33-34
PERF_TIMER_START_BP(PROVE_prime);
aprime = vector_add(vector_scalar(slice(aprime, 0, nprime), w[round]), vector_scalar(slice(aprime, nprime, aprime.size()), winv));
bprime = vector_add(vector_scalar(slice(bprime, 0, nprime), winv), vector_scalar(slice(bprime, nprime, bprime.size()), w[round]));
@@ -776,7 +773,6 @@ try_again:
}
PERF_TIMER_STOP_BP(PROVE_step4);
- // PAPER LINE 58 (with inclusions from PAPER LINE 8 and PAPER LINE 20)
return Bulletproof(std::move(V), A, S, T1, T2, taux, mu, std::move(L), std::move(R), aprime[0], bprime[0], t);
}
@@ -810,7 +806,10 @@ struct proof_data_t
size_t logM, inv_offset;
};
-/* Given a range proof, determine if it is valid */
+/* Given a range proof, determine if it is valid
+ * This uses the method in PAPER LINES 95-105,
+ * weighted across multiple proofs in a batch
+ */
bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
{
init_exponents();
@@ -871,7 +870,6 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
CHECK_AND_ASSERT_MES(rounds > 0, false, "Zero rounds");
PERF_TIMER_START_BP(VERIFY_line_21_22);
- // PAPER LINES 21-22
// The inner product challenges are computed per round
pd.w.resize(rounds);
for (size_t i = 0; i < rounds; ++i)
@@ -929,7 +927,6 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
rct::key proof8_A = rct::scalarmult8(proof.A);
PERF_TIMER_START_BP(VERIFY_line_61);
- // PAPER LINE 61
sc_mulsub(m_y0.bytes, proof.taux.bytes, weight_y.bytes, m_y0.bytes);
const rct::keyV zpow = vector_powers(pd.z, M+3);
@@ -962,7 +959,6 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
PERF_TIMER_STOP_BP(VERIFY_line_61rl_new);
PERF_TIMER_START_BP(VERIFY_line_62);
- // PAPER LINE 62
multiexp_data.emplace_back(weight_z, proof8_A);
sc_mul(tmp.bytes, pd.x.bytes, weight_z.bytes);
multiexp_data.emplace_back(tmp, proof8_S);
@@ -973,7 +969,6 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
CHECK_AND_ASSERT_MES(rounds > 0, false, "Zero rounds");
PERF_TIMER_START_BP(VERIFY_line_24_25);
- // Basically PAPER LINES 24-25
// Compute the curvepoints from G[i] and H[i]
rct::key yinvpow = rct::identity();
rct::key ypow = rct::identity();
@@ -1010,7 +1005,6 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
sc_mul(g_scalar.bytes, g_scalar.bytes, w_cache[i].bytes);
sc_mul(h_scalar.bytes, h_scalar.bytes, w_cache[(~i) & (MN-1)].bytes);
- // Adjust the scalars using the exponents from PAPER LINE 62
sc_add(g_scalar.bytes, g_scalar.bytes, pd.z.bytes);
CHECK_AND_ASSERT_MES(2+i/N < zpow.size(), false, "invalid zpow index");
CHECK_AND_ASSERT_MES(i%N < twoN.size(), false, "invalid twoN index");
@@ -1043,7 +1037,6 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
PERF_TIMER_STOP_BP(VERIFY_line_24_25);
- // PAPER LINE 26
PERF_TIMER_START_BP(VERIFY_line_26_new);
sc_muladd(z1.bytes, proof.mu.bytes, weight_z.bytes, z1.bytes);
for (size_t i = 0; i < rounds; ++i)
diff --git a/src/ringct/rctTypes.cpp b/src/ringct/rctTypes.cpp
index 2c4e5fc3b..1763542db 100644
--- a/src/ringct/rctTypes.cpp
+++ b/src/ringct/rctTypes.cpp
@@ -31,6 +31,7 @@
#include "misc_log_ex.h"
#include "cryptonote_config.h"
#include "rctTypes.h"
+#include "int-util.h"
using namespace crypto;
using namespace std;
@@ -118,40 +119,22 @@ namespace rct {
//uint long long to 32 byte key
void d2h(key & amounth, const xmr_amount in) {
sc_0(amounth.bytes);
- xmr_amount val = in;
- int i = 0;
- while (val != 0) {
- amounth[i] = (unsigned char)(val & 0xFF);
- i++;
- val /= (xmr_amount)256;
- }
+ memcpy_swap64le(amounth.bytes, &in, 1);
}
//uint long long to 32 byte key
key d2h(const xmr_amount in) {
key amounth;
- sc_0(amounth.bytes);
- xmr_amount val = in;
- int i = 0;
- while (val != 0) {
- amounth[i] = (unsigned char)(val & 0xFF);
- i++;
- val /= (xmr_amount)256;
- }
+ d2h(amounth, in);
return amounth;
}
//uint long long to int[64]
void d2b(bits amountb, xmr_amount val) {
int i = 0;
- while (val != 0) {
- amountb[i] = val & 1;
- i++;
- val >>= 1;
- }
while (i < 64) {
- amountb[i] = 0;
- i++;
+ amountb[i++] = val & 1;
+ val >>= 1;
}
}
@@ -172,16 +155,11 @@ namespace rct {
int val = 0, i = 0, j = 0;
for (j = 0; j < 8; j++) {
val = (unsigned char)test.bytes[j];
- i = 8 * j;
- while (val != 0) {
- amountb2[i] = val & 1;
- i++;
+ i = 0;
+ while (i < 8) {
+ amountb2[j*8+i++] = val & 1;
val >>= 1;
}
- while (i < 8 * (j + 1)) {
- amountb2[i] = 0;
- i++;
- }
}
}
diff --git a/src/rpc/CMakeLists.txt b/src/rpc/CMakeLists.txt
index ebb1e767f..65d88b57e 100644
--- a/src/rpc/CMakeLists.txt
+++ b/src/rpc/CMakeLists.txt
@@ -37,6 +37,7 @@ set(rpc_sources
bootstrap_daemon.cpp
core_rpc_server.cpp
rpc_payment.cpp
+ rpc_version_str.cpp
instanciations)
set(daemon_messages_sources
@@ -54,6 +55,7 @@ set(rpc_base_headers
rpc_handler.h)
set(rpc_headers
+ rpc_version_str.h
rpc_handler.h)
set(daemon_rpc_server_headers)
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 9117b5b3a..dc93e7023 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -29,6 +29,7 @@
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#include <boost/preprocessor/stringize.hpp>
+#include <boost/uuid/nil_generator.hpp>
#include "include_base_utils.h"
#include "string_tools.h"
using namespace epee;
@@ -1095,9 +1096,8 @@ namespace cryptonote
}
res.sanity_check_failed = false;
- cryptonote_connection_context fake_context = AUTO_VAL_INIT(fake_context);
- tx_verification_context tvc = AUTO_VAL_INIT(tvc);
- if(!m_core.handle_incoming_tx({tx_blob, crypto::null_hash}, tvc, false, false, req.do_not_relay) || tvc.m_verifivation_failed)
+ tx_verification_context tvc{};
+ if(!m_core.handle_incoming_tx({tx_blob, crypto::null_hash}, tvc, (req.do_not_relay ? relay_method::none : relay_method::local), false) || tvc.m_verifivation_failed)
{
res.status = "Failed";
std::string reason = "";
@@ -1142,7 +1142,7 @@ namespace cryptonote
NOTIFY_NEW_TRANSACTIONS::request r;
r.txs.push_back(tx_blob);
- m_core.get_protocol()->relay_transactions(r, fake_context);
+ m_core.get_protocol()->relay_transactions(r, boost::uuids::nil_uuid(), epee::net_utils::zone::invalid);
//TODO: make sure that tx has reached other nodes here, probably wait to receive reflections from other nodes
res.status = CORE_RPC_STATUS_OK;
return true;
@@ -2370,7 +2370,7 @@ namespace cryptonote
if (req.txids.empty())
{
std::vector<transaction> pool_txs;
- bool r = m_core.get_pool_transactions(pool_txs);
+ bool r = m_core.get_pool_transactions(pool_txs, true);
if (!r)
{
res.status = "Failed to get txpool contents";
@@ -2747,13 +2747,11 @@ namespace cryptonote
crypto::hash txid = *reinterpret_cast<const crypto::hash*>(txid_data.data());
cryptonote::blobdata txblob;
- bool r = m_core.get_pool_transaction(txid, txblob);
- if (r)
+ if (!m_core.get_pool_transaction(txid, txblob, relay_category::legacy))
{
- cryptonote_connection_context fake_context = AUTO_VAL_INIT(fake_context);
NOTIFY_NEW_TRANSACTIONS::request r;
r.txs.push_back(txblob);
- m_core.get_protocol()->relay_transactions(r, fake_context);
+ m_core.get_protocol()->relay_transactions(r, boost::uuids::nil_uuid(), epee::net_utils::zone::invalid);
//TODO: make sure that tx has reached other nodes here, probably wait to receive reflections from other nodes
}
else
diff --git a/src/rpc/daemon_handler.cpp b/src/rpc/daemon_handler.cpp
index d7e081af3..24800ff20 100644
--- a/src/rpc/daemon_handler.cpp
+++ b/src/rpc/daemon_handler.cpp
@@ -28,6 +28,7 @@
#include "daemon_handler.h"
+#include <boost/uuid/nil_generator.hpp>
// likely included by daemon_handler.h's includes,
// but including here for clarity
#include "cryptonote_core/cryptonote_core.h"
@@ -288,10 +289,9 @@ namespace rpc
return;
}
- cryptonote_connection_context fake_context = AUTO_VAL_INIT(fake_context);
tx_verification_context tvc = AUTO_VAL_INIT(tvc);
- if(!m_core.handle_incoming_tx({tx_blob, crypto::null_hash}, tvc, false, false, !relay) || tvc.m_verifivation_failed)
+ if(!m_core.handle_incoming_tx({tx_blob, crypto::null_hash}, tvc, (relay ? relay_method::local : relay_method::none), false) || tvc.m_verifivation_failed)
{
if (tvc.m_verifivation_failed)
{
@@ -311,42 +311,42 @@ namespace rpc
if (tvc.m_double_spend)
{
if (!res.error_details.empty()) res.error_details += " and ";
- res.error_details = "double spend";
+ res.error_details += "double spend";
}
if (tvc.m_invalid_input)
{
if (!res.error_details.empty()) res.error_details += " and ";
- res.error_details = "invalid input";
+ res.error_details += "invalid input";
}
if (tvc.m_invalid_output)
{
if (!res.error_details.empty()) res.error_details += " and ";
- res.error_details = "invalid output";
+ res.error_details += "invalid output";
}
if (tvc.m_too_big)
{
if (!res.error_details.empty()) res.error_details += " and ";
- res.error_details = "too big";
+ res.error_details += "too big";
}
if (tvc.m_overspend)
{
if (!res.error_details.empty()) res.error_details += " and ";
- res.error_details = "overspend";
+ res.error_details += "overspend";
}
if (tvc.m_fee_too_low)
{
if (!res.error_details.empty()) res.error_details += " and ";
- res.error_details = "fee too low";
+ res.error_details += "fee too low";
}
if (tvc.m_not_rct)
{
if (!res.error_details.empty()) res.error_details += " and ";
- res.error_details = "tx is not ringct";
+ res.error_details += "tx is not ringct";
}
if (tvc.m_too_few_outputs)
{
if (!res.error_details.empty()) res.error_details += " and ";
- res.error_details = "too few outputs";
+ res.error_details += "too few outputs";
}
if (res.error_details.empty())
{
@@ -368,7 +368,7 @@ namespace rpc
NOTIFY_NEW_TRANSACTIONS::request r;
r.txs.push_back(tx_blob);
- m_core.get_protocol()->relay_transactions(r, fake_context);
+ m_core.get_protocol()->relay_transactions(r, boost::uuids::nil_uuid(), epee::net_utils::zone::invalid);
//TODO: make sure that tx has reached other nodes here, probably wait to receive reflections from other nodes
res.status = Message::STATUS_OK;
diff --git a/src/rpc/rpc_version_str.cpp b/src/rpc/rpc_version_str.cpp
new file mode 100644
index 000000000..c60cf4891
--- /dev/null
+++ b/src/rpc/rpc_version_str.cpp
@@ -0,0 +1,55 @@
+// Copyright (c) 2019, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "rpc_version_str.h"
+#include "version.h"
+#include <regex>
+
+namespace cryptonote
+{
+
+namespace rpc
+{
+
+// Expected format of Monero software version string:
+// 1) Four numbers, one to two digits each, separated by periods
+// 2) Optionally, one of the following suffixes:
+// a) -release
+// b) -<hash> where <hash> is exactly nine lowercase hex digits
+
+bool is_version_string_valid(const std::string& str)
+{
+ return std::regex_match(str, std::regex(
+ "^\\d{1,2}(\\.\\d{1,2}){3}(-(release|[0-9a-f]{9}))?$",
+ std::regex_constants::nosubs
+ ));
+}
+
+} // namespace rpc
+
+} // namespace cryptonote
diff --git a/src/rpc/rpc_version_str.h b/src/rpc/rpc_version_str.h
new file mode 100644
index 000000000..930c807d2
--- /dev/null
+++ b/src/rpc/rpc_version_str.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2019, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+#pragma once
+
+#include <string>
+
+namespace cryptonote
+{
+
+namespace rpc
+{
+
+bool is_version_string_valid(const std::string& str);
+
+} // namespace rpc
+
+} // namespace cryptonote
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index ea8f6f2f5..87bbf62d3 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -912,16 +912,6 @@ bool simple_wallet::change_password(const std::vector<std::string> &args)
bool simple_wallet::payment_id(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
LONG_PAYMENT_ID_SUPPORT_CHECK();
-
- crypto::hash payment_id;
- if (args.size() > 0)
- {
- PRINT_USAGE(USAGE_PAYMENT_ID);
- return true;
- }
- payment_id = crypto::rand<crypto::hash>();
- success_msg_writer() << tr("Random payment ID: ") << payment_id;
- return true;
}
bool simple_wallet::print_fee_info(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
@@ -4356,7 +4346,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
if (std::cin.eof() || !command_line::is_yes(confirm))
CHECK_AND_ASSERT_MES(false, false, tr("account creation aborted"));
- m_wallet->set_refresh_from_block_height(m_wallet->estimate_blockchain_height());
+ m_wallet->set_refresh_from_block_height(m_wallet->estimate_blockchain_height() > 0 ? m_wallet->estimate_blockchain_height() - 1 : 0);
m_wallet->explicit_refresh_from_block_height(true);
m_restore_height = m_wallet->get_refresh_from_block_height();
}
@@ -6293,13 +6283,6 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
if (tools::wallet2::parse_long_payment_id(payment_id_str, payment_id))
{
LONG_PAYMENT_ID_SUPPORT_CHECK();
-
- std::string extra_nonce;
- set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
- r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
- local_args.pop_back();
- payment_id_seen = true;
- message_writer() << tr("Warning: Unencrypted payment IDs will harm your privacy: ask the recipient to use subaddresses instead");
}
if(!r)
{
@@ -6408,8 +6391,6 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
else if (tools::wallet2::parse_payment_id(payment_id_uri, payment_id))
{
LONG_PAYMENT_ID_SUPPORT_CHECK();
- set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
- message_writer() << tr("Warning: Unencrypted payment IDs will harm your privacy: ask the recipient to use subaddresses instead");
}
else
{
@@ -6945,11 +6926,6 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
if(r)
{
LONG_PAYMENT_ID_SUPPORT_CHECK();
-
- std::string extra_nonce;
- set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
- r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
- payment_id_seen = true;
}
if(!r && local_args.size() == 3)
@@ -7191,7 +7167,6 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
if (tools::wallet2::parse_long_payment_id(local_args.back(), payment_id))
{
LONG_PAYMENT_ID_SUPPORT_CHECK();
- set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
}
else
{
@@ -9421,7 +9396,6 @@ bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::v
if (tools::wallet2::parse_long_payment_id(args[3], payment_id))
{
LONG_PAYMENT_ID_SUPPORT_CHECK();
- description_start += 2;
}
else if (tools::wallet2::parse_short_payment_id(args[3], info.payment_id))
{
diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt
index 3be1a6f6b..a0a166a93 100644
--- a/src/wallet/CMakeLists.txt
+++ b/src/wallet/CMakeLists.txt
@@ -77,42 +77,43 @@ target_link_libraries(wallet
PRIVATE
${EXTRA_LIBRARIES})
-set(wallet_rpc_sources
- wallet_rpc_server.cpp)
+if(NOT IOS)
+ set(wallet_rpc_sources
+ wallet_rpc_server.cpp)
-set(wallet_rpc_headers)
+ set(wallet_rpc_headers)
-set(wallet_rpc_private_headers
- wallet_rpc_server.h)
+ set(wallet_rpc_private_headers
+ wallet_rpc_server.h)
-monero_private_headers(wallet_rpc_server
- ${wallet_rpc_private_headers})
-monero_add_executable(wallet_rpc_server
- ${wallet_rpc_sources}
- ${wallet_rpc_headers}
- ${wallet_rpc_private_headers})
-
-target_link_libraries(wallet_rpc_server
- PRIVATE
- wallet
- rpc_base
- cryptonote_core
- cncrypto
- common
- version
- daemonizer
- ${EPEE_READLINE}
- ${Boost_CHRONO_LIBRARY}
- ${Boost_PROGRAM_OPTIONS_LIBRARY}
- ${Boost_FILESYSTEM_LIBRARY}
- ${Boost_THREAD_LIBRARY}
- ${CMAKE_THREAD_LIBS_INIT}
- ${EXTRA_LIBRARIES})
-set_property(TARGET wallet_rpc_server
- PROPERTY
- OUTPUT_NAME "monero-wallet-rpc")
-install(TARGETS wallet_rpc_server DESTINATION bin)
+ monero_private_headers(wallet_rpc_server
+ ${wallet_rpc_private_headers})
+ monero_add_executable(wallet_rpc_server
+ ${wallet_rpc_sources}
+ ${wallet_rpc_headers}
+ ${wallet_rpc_private_headers})
+ target_link_libraries(wallet_rpc_server
+ PRIVATE
+ wallet
+ rpc_base
+ cryptonote_core
+ cncrypto
+ common
+ version
+ daemonizer
+ ${EPEE_READLINE}
+ ${Boost_CHRONO_LIBRARY}
+ ${Boost_PROGRAM_OPTIONS_LIBRARY}
+ ${Boost_FILESYSTEM_LIBRARY}
+ ${Boost_THREAD_LIBRARY}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${EXTRA_LIBRARIES})
+ set_property(TARGET wallet_rpc_server
+ PROPERTY
+ OUTPUT_NAME "monero-wallet-rpc")
+ install(TARGETS wallet_rpc_server DESTINATION bin)
+endif()
# build and install libwallet_merged only if we building for GUI
if (BUILD_GUI_DEPS)
diff --git a/src/wallet/node_rpc_proxy.cpp b/src/wallet/node_rpc_proxy.cpp
index 15ea26044..005b0bafa 100644
--- a/src/wallet/node_rpc_proxy.cpp
+++ b/src/wallet/node_rpc_proxy.cpp
@@ -36,7 +36,7 @@
do { \
CHECK_AND_ASSERT_MES(error.code == 0, error.message, error.message); \
handle_payment_changes(res, std::integral_constant<bool, HasCredits<decltype(res)>::Has>()); \
- CHECK_AND_ASSERT_MES(r, std::string(), "Failed to connect to daemon"); \
+ CHECK_AND_ASSERT_MES(r, std::string("Failed to connect to daemon"), "Failed to connect to daemon"); \
/* empty string -> not connection */ \
CHECK_AND_ASSERT_MES(!res.status.empty(), res.status, "No connection to daemon"); \
CHECK_AND_ASSERT_MES(res.status != CORE_RPC_STATUS_BUSY, res.status, "Daemon busy"); \
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index e60c6b7e1..4d2ec5103 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1038,10 +1038,15 @@ uint64_t gamma_picker::pick()
return first_rct + crypto::rand_idx(n_rct);
};
+boost::mutex wallet_keys_unlocker::lockers_lock;
+unsigned int wallet_keys_unlocker::lockers = 0;
wallet_keys_unlocker::wallet_keys_unlocker(wallet2 &w, const boost::optional<tools::password_container> &password):
w(w),
locked(password != boost::none)
{
+ boost::lock_guard<boost::mutex> lock(lockers_lock);
+ if (lockers++ > 0)
+ locked = false;
if (!locked || w.is_unattended() || w.ask_password() != tools::wallet2::AskPasswordToDecrypt || w.watch_only())
{
locked = false;
@@ -1056,6 +1061,9 @@ wallet_keys_unlocker::wallet_keys_unlocker(wallet2 &w, bool locked, const epee::
w(w),
locked(locked)
{
+ boost::lock_guard<boost::mutex> lock(lockers_lock);
+ if (lockers++ > 0)
+ locked = false;
if (!locked)
return;
w.generate_chacha_key_from_password(password, key);
@@ -1064,9 +1072,19 @@ wallet_keys_unlocker::wallet_keys_unlocker(wallet2 &w, bool locked, const epee::
wallet_keys_unlocker::~wallet_keys_unlocker()
{
- if (!locked)
- return;
- try { w.encrypt_keys(key); }
+ try
+ {
+ boost::lock_guard<boost::mutex> lock(lockers_lock);
+ if (lockers == 0)
+ {
+ MERROR("There are no lockers in wallet_keys_unlocker dtor");
+ return;
+ }
+ --lockers;
+ if (!locked)
+ return;
+ w.encrypt_keys(key);
+ }
catch (...)
{
MERROR("Failed to re-encrypt wallet keys");
@@ -13601,4 +13619,22 @@ std::vector<cryptonote::public_node> wallet2::get_public_nodes(bool white_only)
std::copy(res.gray.begin(), res.gray.end(), std::back_inserter(nodes));
return nodes;
}
+//----------------------------------------------------------------------------------------------------
+std::pair<size_t, uint64_t> wallet2::estimate_tx_size_and_weight(bool use_rct, int n_inputs, int ring_size, int n_outputs, size_t extra_size)
+{
+ THROW_WALLET_EXCEPTION_IF(n_inputs <= 0, tools::error::wallet_internal_error, "Invalid n_inputs");
+ THROW_WALLET_EXCEPTION_IF(n_outputs < 0, tools::error::wallet_internal_error, "Invalid n_outputs");
+ THROW_WALLET_EXCEPTION_IF(ring_size < 0, tools::error::wallet_internal_error, "Invalid ring size");
+
+ if (ring_size == 0)
+ ring_size = get_min_ring_size();
+ if (n_outputs == 1)
+ n_outputs = 2; // extra dummy output
+
+ const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0);
+ size_t size = estimate_tx_size(use_rct, n_inputs, ring_size - 1, n_outputs, extra_size, bulletproof);
+ uint64_t weight = estimate_tx_weight(use_rct, n_inputs, ring_size - 1, n_outputs, extra_size, bulletproof);
+ return std::make_pair(size, weight);
+}
+//----------------------------------------------------------------------------------------------------
}
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index c86315f7c..8f840a42d 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -122,6 +122,8 @@ private:
wallet2 &w;
bool locked;
crypto::chacha_key key;
+ static boost::mutex lockers_lock;
+ static unsigned int lockers;
};
class i_wallet2_callback
@@ -1252,6 +1254,8 @@ private:
bool is_unattended() const { return m_unattended; }
+ std::pair<size_t, uint64_t> estimate_tx_size_and_weight(bool use_rct, int n_inputs, int ring_size, int n_outputs, size_t extra_size);
+
bool get_rpc_payment_info(bool mining, bool &payment_required, uint64_t &credits, uint64_t &diff, uint64_t &credits_per_hash_found, cryptonote::blobdata &hashing_blob, uint64_t &height, uint64_t &seed_height, crypto::hash &seed_hash, crypto::hash &next_seed_hash, uint32_t &cookie);
bool daemon_requires_payment();
bool make_rpc_payment(uint32_t nonce, uint32_t cookie, uint64_t &credits, uint64_t &balance);
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index de501f056..eb89a96e9 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -550,9 +550,29 @@ namespace tools
if (!m_wallet) return not_open(er);
try
{
- m_wallet->add_subaddress(req.account_index, req.label);
- res.address_index = m_wallet->get_num_subaddresses(req.account_index) - 1;
- res.address = m_wallet->get_subaddress_as_str({req.account_index, res.address_index});
+ if (req.count < 1 || req.count > 64) {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Count must be between 1 and 64.";
+ return false;
+ }
+
+ std::vector<std::string> addresses;
+ std::vector<uint32_t> address_indices;
+
+ addresses.reserve(req.count);
+ address_indices.reserve(req.count);
+
+ for (uint32_t i = 0; i < req.count; i++) {
+ m_wallet->add_subaddress(req.account_index, req.label);
+ uint32_t new_address_index = m_wallet->get_num_subaddresses(req.account_index) - 1;
+ address_indices.push_back(new_address_index);
+ addresses.push_back(m_wallet->get_subaddress_as_str({req.account_index, new_address_index}));
+ }
+
+ res.address = addresses[0];
+ res.address_index = address_indices[0];
+ res.addresses = addresses;
+ res.address_indices = address_indices;
}
catch (const std::exception& e)
{
@@ -4291,6 +4311,25 @@ namespace tools
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
+ bool wallet_rpc_server::on_estimate_tx_size_and_weight(const wallet_rpc::COMMAND_RPC_ESTIMATE_TX_SIZE_AND_WEIGHT::request& req, wallet_rpc::COMMAND_RPC_ESTIMATE_TX_SIZE_AND_WEIGHT::response& res, epee::json_rpc::error& er, const connection_context *ctx)
+ {
+ if (!m_wallet) return not_open(er);
+ try
+ {
+ size_t extra_size = 34 /* pubkey */ + 10 /* encrypted payment id */; // typical makeup
+ const std::pair<size_t, uint64_t> sw = m_wallet->estimate_tx_size_and_weight(req.rct, req.n_inputs, req.ring_size, req.n_outputs, extra_size);
+ res.size = sw.first;
+ res.weight = sw.second;
+ }
+ catch (const std::exception &e)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Failed to determine size and weight";
+ return false;
+ }
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_get_version(const wallet_rpc::COMMAND_RPC_GET_VERSION::request& req, wallet_rpc::COMMAND_RPC_GET_VERSION::response& res, epee::json_rpc::error& er, const connection_context *ctx)
{
res.version = WALLET_RPC_VERSION;
diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h
index b2b5e7116..41f6879ef 100644
--- a/src/wallet/wallet_rpc_server.h
+++ b/src/wallet/wallet_rpc_server.h
@@ -154,6 +154,7 @@ namespace tools
MAP_JON_RPC_WE("set_daemon", on_set_daemon, wallet_rpc::COMMAND_RPC_SET_DAEMON)
MAP_JON_RPC_WE("set_log_level", on_set_log_level, wallet_rpc::COMMAND_RPC_SET_LOG_LEVEL)
MAP_JON_RPC_WE("set_log_categories", on_set_log_categories, wallet_rpc::COMMAND_RPC_SET_LOG_CATEGORIES)
+ MAP_JON_RPC_WE("estimate_tx_size_and_weight", on_estimate_tx_size_and_weight, wallet_rpc::COMMAND_RPC_ESTIMATE_TX_SIZE_AND_WEIGHT)
MAP_JON_RPC_WE("get_version", on_get_version, wallet_rpc::COMMAND_RPC_GET_VERSION)
END_JSON_RPC_MAP()
END_URI_MAP2()
@@ -240,6 +241,7 @@ namespace tools
bool on_set_daemon(const wallet_rpc::COMMAND_RPC_SET_DAEMON::request& req, wallet_rpc::COMMAND_RPC_SET_DAEMON::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_set_log_level(const wallet_rpc::COMMAND_RPC_SET_LOG_LEVEL::request& req, wallet_rpc::COMMAND_RPC_SET_LOG_LEVEL::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_set_log_categories(const wallet_rpc::COMMAND_RPC_SET_LOG_CATEGORIES::request& req, wallet_rpc::COMMAND_RPC_SET_LOG_CATEGORIES::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
+ bool on_estimate_tx_size_and_weight(const wallet_rpc::COMMAND_RPC_ESTIMATE_TX_SIZE_AND_WEIGHT::request& req, wallet_rpc::COMMAND_RPC_ESTIMATE_TX_SIZE_AND_WEIGHT::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_get_version(const wallet_rpc::COMMAND_RPC_GET_VERSION::request& req, wallet_rpc::COMMAND_RPC_GET_VERSION::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
//json rpc v2
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index 0c86f404d..8d601b050 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -47,7 +47,7 @@
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define WALLET_RPC_VERSION_MAJOR 1
-#define WALLET_RPC_VERSION_MINOR 16
+#define WALLET_RPC_VERSION_MINOR 17
#define MAKE_WALLET_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define WALLET_RPC_VERSION MAKE_WALLET_RPC_VERSION(WALLET_RPC_VERSION_MAJOR, WALLET_RPC_VERSION_MINOR)
namespace tools
@@ -182,11 +182,13 @@ namespace wallet_rpc
{
struct request_t
{
- uint32_t account_index;
+ uint32_t account_index;
+ uint32_t count;
std::string label;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(account_index)
+ KV_SERIALIZE_OPT(count, 1U)
KV_SERIALIZE(label)
END_KV_SERIALIZE_MAP()
};
@@ -194,12 +196,16 @@ namespace wallet_rpc
struct response_t
{
- std::string address;
- uint32_t address_index;
+ std::string address;
+ uint32_t address_index;
+ std::vector<std::string> addresses;
+ std::vector<uint32_t> address_indices;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(address)
KV_SERIALIZE(address_index)
+ KV_SERIALIZE(addresses)
+ KV_SERIALIZE(address_indices)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -2580,5 +2586,36 @@ namespace wallet_rpc
typedef epee::misc_utils::struct_init<response_t> response;
};
+ struct COMMAND_RPC_ESTIMATE_TX_SIZE_AND_WEIGHT
+ {
+ struct request_t
+ {
+ uint32_t n_inputs;
+ uint32_t n_outputs;
+ uint32_t ring_size;
+ bool rct;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(n_inputs)
+ KV_SERIALIZE(n_outputs)
+ KV_SERIALIZE_OPT(ring_size, 0u)
+ KV_SERIALIZE_OPT(rct, true)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<request_t> request;
+
+ struct response_t
+ {
+ uint64_t size;
+ uint64_t weight;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(size)
+ KV_SERIALIZE(weight)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<response_t> response;
+ };
+
}
}