aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt5
-rw-r--r--src/blockchain_db/berkeleydb/db_bdb.cpp27
-rw-r--r--src/blockchain_db/berkeleydb/db_bdb.h18
-rw-r--r--src/blockchain_db/blockchain_db.cpp10
-rw-r--r--src/blockchain_db/blockchain_db.h4
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp42
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h24
-rw-r--r--src/checkpoints/checkpoints.cpp4
-rw-r--r--src/common/CMakeLists.txt4
-rw-r--r--src/common/compat/glibc_compat.cpp98
-rw-r--r--src/common/perf_timer.cpp46
-rw-r--r--src/common/perf_timer.h6
-rw-r--r--src/common/spawn.cpp4
-rw-r--r--src/common/util.cpp32
-rw-r--r--src/cryptonote_basic/cryptonote_basic.h2
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.cpp19
-rw-r--r--src/cryptonote_core/blockchain.cpp25
-rw-r--r--src/cryptonote_core/blockchain.h5
-rw-r--r--src/cryptonote_core/tx_pool.cpp23
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.h2
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl34
-rw-r--r--src/device_trezor/CMakeLists.txt8
-rw-r--r--src/mnemonics/singleton.h4
-rw-r--r--src/p2p/net_node.h6
-rw-r--r--src/p2p/net_node.inl10
-rw-r--r--src/p2p/net_peerlist.h15
-rw-r--r--src/p2p/p2p_protocol_defs.h20
-rw-r--r--src/rpc/core_rpc_server.cpp7
-rw-r--r--src/simplewallet/simplewallet.cpp475
-rw-r--r--src/simplewallet/simplewallet.h2
-rw-r--r--src/wallet/CMakeLists.txt6
-rw-r--r--src/wallet/wallet2.cpp82
-rw-r--r--src/wallet/wallet2.h17
33 files changed, 713 insertions, 373 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6ee7effdd..a0b62da77 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -34,11 +34,6 @@ if (WIN32 OR STATIC)
add_definitions(-DMINIUPNP_STATICLIB)
endif ()
-# warnings are cleared only for GCC on Linux
-if (NOT (MINGW OR APPLE OR FREEBSD OR OPENBSD OR DRAGONFLY))
- add_compile_options("${WARNINGS_AS_ERRORS_FLAG}") # applies only to targets that follow
-endif()
-
function (monero_private_headers group)
source_group("${group}\\Private"
FILES
diff --git a/src/blockchain_db/berkeleydb/db_bdb.cpp b/src/blockchain_db/berkeleydb/db_bdb.cpp
index 6c79120e8..60a7326f8 100644
--- a/src/blockchain_db/berkeleydb/db_bdb.cpp
+++ b/src/blockchain_db/berkeleydb/db_bdb.cpp
@@ -714,29 +714,6 @@ bool BlockchainBDB::for_all_outputs(std::function<bool(uint64_t amount, const cr
return ret;
}
-blobdata BlockchainBDB::output_to_blob(const tx_out& output) const
-{
- LOG_PRINT_L3("BlockchainBDB::" << __func__);
- blobdata b;
- if (!t_serializable_object_to_blob(output, b))
- throw1(DB_ERROR("Error serializing output to blob"));
- return b;
-}
-
-tx_out BlockchainBDB::output_from_blob(const blobdata& blob) const
-{
- LOG_PRINT_L3("BlockchainBDB::" << __func__);
- std::stringstream ss;
- ss << blob;
- binary_archive<false> ba(ss);
- tx_out o;
-
- if (!(::serialization::serialize(ba, o)))
- throw1(DB_ERROR("Error deserializing tx output blob"));
-
- return o;
-}
-
uint64_t BlockchainBDB::get_output_global_index(const uint64_t& amount, const uint64_t& index)
{
LOG_PRINT_L3("BlockchainBDB::" << __func__);
@@ -1655,7 +1632,7 @@ output_data_t BlockchainBDB::get_output_key(const uint64_t& global_index) const
return v;
}
-output_data_t BlockchainBDB::get_output_key(const uint64_t& amount, const uint64_t& index)
+output_data_t BlockchainBDB::get_output_key(const uint64_t& amount, const uint64_t& index) const
{
LOG_PRINT_L3("BlockchainBDB::" << __func__);
check_open();
@@ -1664,7 +1641,7 @@ output_data_t BlockchainBDB::get_output_key(const uint64_t& amount, const uint64
return get_output_key(glob_index);
}
-tx_out_index BlockchainBDB::get_output_tx_and_index(const uint64_t& amount, const uint64_t& index)
+tx_out_index BlockchainBDB::get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) const
{
LOG_PRINT_L3("BlockchainBDB::" << __func__);
std::vector < uint64_t > offsets;
diff --git a/src/blockchain_db/berkeleydb/db_bdb.h b/src/blockchain_db/berkeleydb/db_bdb.h
index 76d0a0517..e80adae9e 100644
--- a/src/blockchain_db/berkeleydb/db_bdb.h
+++ b/src/blockchain_db/berkeleydb/db_bdb.h
@@ -392,24 +392,6 @@ private:
virtual void drop_hard_fork_info();
/**
- * @brief convert a tx output to a blob for storage
- *
- * @param output the output to convert
- *
- * @return the resultant blob
- */
- blobdata output_to_blob(const tx_out& output) const;
-
- /**
- * @brief convert a tx output blob to a tx output
- *
- * @param blob the blob to convert
- *
- * @return the resultant tx output
- */
- tx_out output_from_blob(const blobdata& blob) const;
-
- /**
* @brief get the global index of the index-th output of the given amount
*
* @param amount the output amount
diff --git a/src/blockchain_db/blockchain_db.cpp b/src/blockchain_db/blockchain_db.cpp
index be0ffeac3..c25798c1e 100644
--- a/src/blockchain_db/blockchain_db.cpp
+++ b/src/blockchain_db/blockchain_db.cpp
@@ -170,7 +170,7 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transacti
uint64_t tx_id = add_transaction_data(blk_hash, tx, tx_hash, tx_prunable_hash);
- std::vector<uint64_t> amount_output_indices;
+ std::vector<uint64_t> amount_output_indices(tx.vout.size());
// iterate tx.vout using indices instead of C++11 foreach syntax because
// we need the index
@@ -183,13 +183,13 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transacti
cryptonote::tx_out vout = tx.vout[i];
rct::key commitment = rct::zeroCommit(vout.amount);
vout.amount = 0;
- amount_output_indices.push_back(add_output(tx_hash, vout, i, tx.unlock_time,
- &commitment));
+ amount_output_indices[i] = add_output(tx_hash, vout, i, tx.unlock_time,
+ &commitment);
}
else
{
- amount_output_indices.push_back(add_output(tx_hash, tx.vout[i], i, tx.unlock_time,
- tx.version > 1 ? &tx.rct_signatures.outPk[i].mask : NULL));
+ amount_output_indices[i] = add_output(tx_hash, tx.vout[i], i, tx.unlock_time,
+ tx.version > 1 ? &tx.rct_signatures.outPk[i].mask : NULL);
}
}
add_tx_amount_output_indices(tx_id, amount_output_indices);
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index f13aa0cae..9d4f59b3c 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -1258,7 +1258,7 @@ public:
*
* @return the requested output data
*/
- virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) = 0;
+ virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) const = 0;
/**
* @brief gets an output's tx hash and index
@@ -1310,7 +1310,7 @@ public:
* @param offsets a list of amount-specific output indices
* @param outputs return-by-reference a list of outputs' metadata
*/
- virtual void get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial = false) = 0;
+ virtual void get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial = false) const = 0;
/*
* FIXME: Need to check with git blame and ask what this does to
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index 4bfc80863..77f8ade7f 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -456,6 +456,12 @@ inline int lmdb_txn_renew(MDB_txn *txn)
return res;
}
+inline void BlockchainLMDB::check_open() const
+{
+ if (!m_open)
+ throw0(DB_ERROR("DB operation attempted on a not-open DB instance"));
+}
+
void BlockchainLMDB::do_resize(uint64_t increase_size)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@@ -1166,36 +1172,6 @@ void BlockchainLMDB::remove_spent_key(const crypto::key_image& k_image)
}
}
-blobdata BlockchainLMDB::output_to_blob(const tx_out& output) const
-{
- LOG_PRINT_L3("BlockchainLMDB::" << __func__);
- blobdata b;
- if (!t_serializable_object_to_blob(output, b))
- throw1(DB_ERROR("Error serializing output to blob"));
- return b;
-}
-
-tx_out BlockchainLMDB::output_from_blob(const blobdata& blob) const
-{
- LOG_PRINT_L3("BlockchainLMDB::" << __func__);
- std::stringstream ss;
- ss << blob;
- binary_archive<false> ba(ss);
- tx_out o;
-
- if (!(::serialization::serialize(ba, o)))
- throw1(DB_ERROR("Error deserializing tx output blob"));
-
- return o;
-}
-
-void BlockchainLMDB::check_open() const
-{
-// LOG_PRINT_L3("BlockchainLMDB::" << __func__);
- if (!m_open)
- throw0(DB_ERROR("DB operation attempted on a not-open DB instance"));
-}
-
BlockchainLMDB::~BlockchainLMDB()
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@@ -2559,7 +2535,7 @@ uint64_t BlockchainLMDB::get_num_outputs(const uint64_t& amount) const
return num_elems;
}
-output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint64_t& index)
+output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint64_t& index) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@@ -3192,7 +3168,7 @@ uint64_t BlockchainLMDB::add_block(const block& blk, size_t block_weight, const
check_open();
uint64_t m_height = height();
- if (m_height % 1000 == 0)
+ if (m_height % 1024 == 0)
{
// for batch mode, DB resize check is done at start of batch transaction
if (! m_batch_active && need_resize())
@@ -3266,7 +3242,7 @@ void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector<uint6
TXN_POSTFIX_RDONLY();
}
-void BlockchainLMDB::get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial)
+void BlockchainLMDB::get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial) const
{
if (amounts.size() != 1 && amounts.size() != offsets.size())
throw0(DB_ERROR("Invalid sizes of amounts and offets"));
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index 6db241240..60797a076 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -242,8 +242,8 @@ public:
virtual uint64_t get_num_outputs(const uint64_t& amount) const;
- virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index);
- virtual void get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial = false);
+ virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) const;
+ virtual void get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial = false) const;
virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const;
virtual void get_output_tx_and_index_from_global(const std::vector<uint64_t> &global_indices,
@@ -359,25 +359,7 @@ private:
virtual void check_hard_fork_info();
virtual void drop_hard_fork_info();
- /**
- * @brief convert a tx output to a blob for storage
- *
- * @param output the output to convert
- *
- * @return the resultant blob
- */
- blobdata output_to_blob(const tx_out& output) const;
-
- /**
- * @brief convert a tx output blob to a tx output
- *
- * @param blob the blob to convert
- *
- * @return the resultant tx output
- */
- tx_out output_from_blob(const blobdata& blob) const;
-
- void check_open() const;
+ inline void check_open() const;
virtual bool is_read_only() const;
diff --git a/src/checkpoints/checkpoints.cpp b/src/checkpoints/checkpoints.cpp
index 1807d44d9..96f575b2d 100644
--- a/src/checkpoints/checkpoints.cpp
+++ b/src/checkpoints/checkpoints.cpp
@@ -74,7 +74,7 @@ namespace cryptonote
bool checkpoints::add_checkpoint(uint64_t height, const std::string& hash_str)
{
crypto::hash h = crypto::null_hash;
- bool r = epee::string_tools::parse_tpod_from_hex_string(hash_str, h);
+ bool r = epee::string_tools::hex_to_pod(hash_str, h);
CHECK_AND_ASSERT_MES(r, false, "Failed to parse checkpoint hash string into binary representation!");
// return false if adding at a height we already have AND the hash is different
@@ -292,7 +292,7 @@ namespace cryptonote
// parse the second part as crypto::hash,
// if this fails move on to the next record
std::string hashStr = record.substr(pos + 1);
- if (!epee::string_tools::parse_tpod_from_hex_string(hashStr, hash))
+ if (!epee::string_tools::hex_to_pod(hashStr, hash))
{
continue;
}
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 5da23c944..3b1eb6d23 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -50,6 +50,10 @@ if (STACK_TRACE)
list(APPEND common_sources stack_trace.cpp)
endif()
+if (BACKCOMPAT)
+ list(APPEND common_sources compat/glibc_compat.cpp)
+endif()
+
set(common_headers)
set(common_private_headers
diff --git a/src/common/compat/glibc_compat.cpp b/src/common/compat/glibc_compat.cpp
new file mode 100644
index 000000000..bf567987d
--- /dev/null
+++ b/src/common/compat/glibc_compat.cpp
@@ -0,0 +1,98 @@
+#include <cstddef>
+#include <cstdint>
+#include <strings.h>
+#include <string.h>
+#include <glob.h>
+#include <unistd.h>
+#include <fnmatch.h>
+
+#if defined(HAVE_SYS_SELECT_H)
+#include <sys/select.h>
+#endif
+
+// Prior to GLIBC_2.14, memcpy was aliased to memmove.
+extern "C" void* memmove(void* a, const void* b, size_t c);
+//extern "C" void* memset(void* a, int b, long unsigned int c);
+extern "C" void* memcpy(void* a, const void* b, size_t c)
+{
+ return memmove(a, b, c);
+}
+
+extern "C" void __chk_fail(void) __attribute__((__noreturn__));
+
+#if defined(__i386__) || defined(__arm__)
+
+extern "C" int64_t __udivmoddi4(uint64_t u, uint64_t v, uint64_t* rp);
+
+extern "C" int64_t __wrap___divmoddi4(int64_t u, int64_t v, int64_t* rp)
+{
+ int32_t c1 = 0, c2 = 0;
+ int64_t uu = u, vv = v;
+ int64_t w;
+ int64_t r;
+
+ if (uu < 0) {
+ c1 = ~c1, c2 = ~c2, uu = -uu;
+ }
+ if (vv < 0) {
+ c1 = ~c1, vv = -vv;
+ }
+
+ w = __udivmoddi4(uu, vv, (uint64_t*)&r);
+ if (c1)
+ w = -w;
+ if (c2)
+ r = -r;
+
+ *rp = r;
+ return w;
+}
+#endif
+
+/* glibc-internal users use __explicit_bzero_chk, and explicit_bzero
+ redirects to that. */
+#undef explicit_bzero
+/* Set LEN bytes of S to 0. The compiler will not delete a call to
+ this function, even if S is dead after the call. */
+void
+explicit_bzero (void *s, size_t len)
+{
+ memset (s, '\0', len);
+ /* Compiler barrier. */
+ asm volatile ("" ::: "memory");
+}
+
+// Redefine explicit_bzero_chk
+void
+__explicit_bzero_chk (void *dst, size_t len, size_t dstlen)
+{
+ /* Inline __memset_chk to avoid a PLT reference to __memset_chk. */
+ if (__glibc_unlikely (dstlen < len))
+ __chk_fail ();
+ memset (dst, '\0', len);
+ /* Compiler barrier. */
+ asm volatile ("" ::: "memory");
+}
+/* libc-internal references use the hidden
+ __explicit_bzero_chk_internal symbol. This is necessary if
+ __explicit_bzero_chk is implemented as an IFUNC because some
+ targets do not support hidden references to IFUNC symbols. */
+#define strong_alias (__explicit_bzero_chk, __explicit_bzero_chk_internal)
+
+#undef glob
+extern "C" int glob_old(const char * pattern, int flags, int (*errfunc) (const char *epath, int eerrno), glob_t *pglob);
+#ifdef __i386__
+__asm__(".symver glob_old,glob@GLIBC_2.1");
+#elif defined(__amd64__)
+__asm__(".symver glob_old,glob@GLIBC_2.2.5");
+#elif defined(__arm__)
+__asm(".symver glob_old,glob@GLIBC_2.4");
+#elif defined(__aarch64__)
+__asm__(".symver glob_old,glob@GLIBC_2.17");
+#endif
+
+extern "C" int __wrap_glob(const char * pattern, int flags, int (*errfunc) (const char *epath, int eerrno), glob_t *pglob)
+{
+ return glob_old(pattern, flags, errfunc, pglob);
+}
+
diff --git a/src/common/perf_timer.cpp b/src/common/perf_timer.cpp
index d9f1f65c1..3e1357833 100644
--- a/src/common/perf_timer.cpp
+++ b/src/common/perf_timer.cpp
@@ -33,6 +33,13 @@
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "perf"
+#define PERF_LOG_ALWAYS(level, cat, x) \
+ el::base::Writer(level, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::FileOnlyLog).construct(cat) << x
+#define PERF_LOG(level, cat, x) \
+ do { \
+ if (ELPP->vRegistry()->allowed(level, cat)) PERF_LOG_ALWAYS(level, cat, x); \
+ } while(0)
+
namespace tools
{
uint64_t get_tick_count()
@@ -106,9 +113,11 @@ PerformanceTimer::PerformanceTimer(bool paused): started(true), paused(paused)
LoggingPerformanceTimer::LoggingPerformanceTimer(const std::string &s, const std::string &cat, uint64_t unit, el::Level l): PerformanceTimer(), name(s), cat(cat), unit(unit), level(l)
{
+ const bool log = ELPP->vRegistry()->allowed(level, cat.c_str());
if (!performance_timers)
{
- MCLOG(level, cat.c_str(), "PERF ----------");
+ if (log)
+ PERF_LOG_ALWAYS(level, cat.c_str(), "PERF ----------");
performance_timers = new std::vector<LoggingPerformanceTimer*>();
performance_timers->reserve(16); // how deep before realloc
}
@@ -117,8 +126,11 @@ LoggingPerformanceTimer::LoggingPerformanceTimer(const std::string &s, const std
LoggingPerformanceTimer *pt = performance_timers->back();
if (!pt->started && !pt->paused)
{
- size_t size = 0; for (const auto *tmp: *performance_timers) if (!tmp->paused) ++size;
- MCLOG(pt->level, cat.c_str(), "PERF " << std::string((size-1) * 2, ' ') << " " << pt->name);
+ if (log)
+ {
+ size_t size = 0; for (const auto *tmp: *performance_timers) if (!tmp->paused) ++size;
+ PERF_LOG_ALWAYS(pt->level, cat.c_str(), "PERF " << std::string((size-1) * 2, ' ') << " " << pt->name);
+ }
pt->started = true;
}
}
@@ -135,10 +147,14 @@ LoggingPerformanceTimer::~LoggingPerformanceTimer()
{
pause();
performance_timers->pop_back();
- char s[12];
- snprintf(s, sizeof(s), "%8llu ", (unsigned long long)(ticks_to_ns(ticks) / (1000000000 / unit)));
- size_t size = 0; for (const auto *tmp: *performance_timers) if (!tmp->paused || tmp==this) ++size;
- MCLOG(level, cat.c_str(), "PERF " << s << std::string(size * 2, ' ') << " " << name);
+ const bool log = ELPP->vRegistry()->allowed(level, cat.c_str());
+ if (log)
+ {
+ char s[12];
+ snprintf(s, sizeof(s), "%8llu ", (unsigned long long)(ticks_to_ns(ticks) / (1000000000 / unit)));
+ size_t size = 0; for (const auto *tmp: *performance_timers) if (!tmp->paused || tmp==this) ++size;
+ PERF_LOG_ALWAYS(level, cat.c_str(), "PERF " << s << std::string(size * 2, ' ') << " " << name);
+ }
if (performance_timers->empty())
{
delete performance_timers;
@@ -162,4 +178,20 @@ void PerformanceTimer::resume()
paused = false;
}
+void PerformanceTimer::reset()
+{
+ if (paused)
+ ticks = 0;
+ else
+ ticks = get_tick_count();
+}
+
+uint64_t PerformanceTimer::value() const
+{
+ uint64_t v = ticks;
+ if (!paused)
+ v = get_tick_count() - v;
+ return ticks_to_ns(v);
+}
+
}
diff --git a/src/common/perf_timer.h b/src/common/perf_timer.h
index 584434a0d..d859cf576 100644
--- a/src/common/perf_timer.h
+++ b/src/common/perf_timer.h
@@ -51,8 +51,8 @@ public:
~PerformanceTimer();
void pause();
void resume();
-
- uint64_t value() const { return ticks; }
+ void reset();
+ uint64_t value() const;
protected:
uint64_t ticks;
@@ -63,7 +63,7 @@ protected:
class LoggingPerformanceTimer: public PerformanceTimer
{
public:
- LoggingPerformanceTimer(const std::string &s, const std::string &cat, uint64_t unit, el::Level l = el::Level::Debug);
+ LoggingPerformanceTimer(const std::string &s, const std::string &cat, uint64_t unit, el::Level l = el::Level::Info);
~LoggingPerformanceTimer();
private:
diff --git a/src/common/spawn.cpp b/src/common/spawn.cpp
index 0a2ce8387..b2d03f62f 100644
--- a/src/common/spawn.cpp
+++ b/src/common/spawn.cpp
@@ -35,6 +35,7 @@
#include <windows.h>
#else
#include <sys/wait.h>
+#include <signal.h>
#endif
#include "misc_log_ex.h"
@@ -114,7 +115,10 @@ int spawn(const char *filename, const std::vector<std::string>& args, bool wait)
if (pid > 0)
{
if (!wait)
+ {
+ signal(SIGCHLD, SIG_IGN);
return 0;
+ }
while (1)
{
diff --git a/src/common/util.cpp b/src/common/util.cpp
index 448f792ff..28745eea4 100644
--- a/src/common/util.cpp
+++ b/src/common/util.cpp
@@ -82,6 +82,32 @@ using namespace epee;
#include <boost/asio.hpp>
#include <openssl/sha.h>
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "util"
+
+namespace
+{
+
+#ifndef _WIN32
+static int flock_exnb(int fd)
+{
+ struct flock fl;
+ int ret;
+
+ memset(&fl, 0, sizeof(fl));
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 0;
+ ret = fcntl(fd, F_SETLK, &fl);
+ if (ret < 0)
+ MERROR("Error locking fd " << fd << ": " << errno << " (" << strerror(errno) << ")");
+ return ret;
+}
+#endif
+
+}
+
namespace tools
{
std::function<void(int)> signal_handler::m_handler;
@@ -182,7 +208,7 @@ namespace tools
struct stat wstats = {};
if (fstat(fdw, std::addressof(wstats)) == 0 &&
rstats.st_dev == wstats.st_dev && rstats.st_ino == wstats.st_ino &&
- flock(fdw, (LOCK_EX | LOCK_NB)) == 0 && ftruncate(fdw, 0) == 0)
+ flock_exnb(fdw) == 0 && ftruncate(fdw, 0) == 0)
{
std::FILE* file = fdopen(fdw, "w");
if (file) return {file, std::move(name)};
@@ -235,10 +261,10 @@ namespace tools
MERROR("Failed to open " << filename << ": " << std::error_code(GetLastError(), std::system_category()));
}
#else
- m_fd = open(filename.c_str(), O_RDONLY | O_CREAT | O_CLOEXEC, 0666);
+ m_fd = open(filename.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0666);
if (m_fd != -1)
{
- if (flock(m_fd, LOCK_EX | LOCK_NB) == -1)
+ if (flock_exnb(m_fd) == -1)
{
MERROR("Failed to lock " << filename << ": " << std::strerror(errno));
close(m_fd);
diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h
index 645e99f91..196b20e2a 100644
--- a/src/cryptonote_basic/cryptonote_basic.h
+++ b/src/cryptonote_basic/cryptonote_basic.h
@@ -211,6 +211,8 @@ namespace cryptonote
void set_hash_valid(bool v) const { hash_valid.store(v,std::memory_order_release); }
bool is_blob_size_valid() const { return blob_size_valid.load(std::memory_order_acquire); }
void set_blob_size_valid(bool v) const { blob_size_valid.store(v,std::memory_order_release); }
+ void set_hash(const crypto::hash &h) { hash = h; set_hash_valid(true); }
+ void set_blob_size(size_t sz) { blob_size = sz; set_blob_size_valid(true); }
BEGIN_SERIALIZE_OBJECT()
if (!typename Archive<W>::is_saving())
diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp
index 55d7d23f8..82428f196 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.cpp
+++ b/src/cryptonote_basic/cryptonote_format_utils.cpp
@@ -184,6 +184,7 @@ namespace cryptonote
CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob");
CHECK_AND_ASSERT_MES(expand_transaction_1(tx, false), false, "Failed to expand transaction data");
tx.invalidate_hashes();
+ tx.set_blob_size(tx_blob.size());
return true;
}
//---------------------------------------------------------------
@@ -379,11 +380,19 @@ namespace cryptonote
//---------------------------------------------------------------
uint64_t get_transaction_weight(const transaction &tx)
{
- std::ostringstream s;
- binary_archive<true> a(s);
- ::serialization::serialize(a, const_cast<transaction&>(tx));
- const cryptonote::blobdata blob = s.str();
- return get_transaction_weight(tx, blob.size());
+ size_t blob_size;
+ if (tx.is_blob_size_valid())
+ {
+ blob_size = tx.blob_size;
+ }
+ else
+ {
+ std::ostringstream s;
+ binary_archive<true> a(s);
+ ::serialization::serialize(a, const_cast<transaction&>(tx));
+ blob_size = s.str().size();
+ }
+ return get_transaction_weight(tx, blob_size);
}
//---------------------------------------------------------------
bool get_tx_fee(const transaction& tx, uint64_t & fee)
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index c6a3c6180..bbac20eaa 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -171,6 +171,11 @@ Blockchain::Blockchain(tx_memory_pool& tx_pool) :
LOG_PRINT_L3("Blockchain::" << __func__);
}
//------------------------------------------------------------------
+Blockchain::~Blockchain()
+{
+ deinit();
+}
+//------------------------------------------------------------------
bool Blockchain::have_tx(const crypto::hash &id) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
@@ -550,15 +555,13 @@ bool Blockchain::deinit()
// as this should be called if handling a SIGSEGV, need to check
// if m_db is a NULL pointer (and thus may have caused the illegal
// memory operation), otherwise we may cause a loop.
- if (m_db == NULL)
- {
- throw DB_ERROR("The db pointer is null in Blockchain, the blockchain may be corrupt!");
- }
-
try
{
- m_db->close();
- MTRACE("Local blockchain read/write activity stopped successfully");
+ if (m_db)
+ {
+ m_db->close();
+ MTRACE("Local blockchain read/write activity stopped successfully");
+ }
}
catch (const std::exception& e)
{
@@ -1269,7 +1272,9 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
uint64_t already_generated_coins;
uint64_t pool_cookie;
- CRITICAL_REGION_BEGIN(m_blockchain_lock);
+ m_tx_pool.lock();
+ const auto unlock_guard = epee::misc_utils::create_scope_leave_handler([&]() { m_tx_pool.unlock(); });
+ CRITICAL_REGION_LOCAL(m_blockchain_lock);
height = m_db->height();
if (m_btc_valid) {
// The pool cookie is atomic. The lack of locking is OK, as if it changes
@@ -1305,8 +1310,6 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
median_weight = m_current_block_cumul_weight_limit / 2;
already_generated_coins = m_db->get_block_already_generated_coins(height - 1);
- CRITICAL_REGION_END();
-
size_t txs_weight;
uint64_t fee;
if (!m_tx_pool.fill_block_template(b, median_weight, already_generated_coins, txs_weight, fee, expected_reward, m_hardfork->get_current_version()))
@@ -1317,7 +1320,6 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
size_t real_txs_weight = 0;
uint64_t real_fee = 0;
- CRITICAL_REGION_BEGIN(m_tx_pool.m_transactions_lock);
for(crypto::hash &cur_hash: b.tx_hashes)
{
auto cur_res = m_tx_pool.m_transactions.find(cur_hash);
@@ -1361,7 +1363,6 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
{
LOG_ERROR("Creating block template: error: wrongly calculated fee");
}
- CRITICAL_REGION_END();
MDEBUG("Creating block template: height " << height <<
", median weight " << median_weight <<
", already generated coins " << already_generated_coins <<
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index 877828f81..67bccc6c6 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -121,6 +121,11 @@ namespace cryptonote
Blockchain(tx_memory_pool& tx_pool);
/**
+ * @brief Blockchain destructor
+ */
+ ~Blockchain();
+
+ /**
* @brief Initialize the Blockchain state
*
* @param db a pointer to the backing store to use for the blockchain
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index d4b4e4d34..1c8f1c62c 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -480,6 +480,10 @@ namespace cryptonote
MERROR("Failed to parse tx from txpool");
return false;
}
+ else
+ {
+ tx.set_hash(id);
+ }
tx_weight = meta.weight;
fee = meta.fee;
relayed = meta.relayed;
@@ -659,7 +663,8 @@ namespace cryptonote
// continue
return true;
}
- txs.push_back(tx);
+ tx.set_hash(txid);
+ txs.push_back(std::move(tx));
return true;
}, true, include_unrelayed_txes);
}
@@ -782,6 +787,7 @@ namespace cryptonote
// continue
return true;
}
+ tx.set_hash(txid);
txi.tx_json = obj_to_json_str(tx);
txi.blob_size = bd->size();
txi.weight = meta.weight;
@@ -798,7 +804,7 @@ namespace cryptonote
txi.last_relayed_time = include_sensitive_data ? meta.last_relayed_time : 0;
txi.do_not_relay = meta.do_not_relay;
txi.double_spend_seen = meta.double_spend_seen;
- tx_infos.push_back(txi);
+ tx_infos.push_back(std::move(txi));
return true;
}, true, include_sensitive_data);
@@ -847,14 +853,13 @@ namespace cryptonote
m_blockchain.for_all_txpool_txes([&tx_infos, key_image_infos](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
cryptonote::rpc::tx_in_pool txi;
txi.tx_hash = txid;
- transaction tx;
- if (!parse_and_validate_tx_from_blob(*bd, tx))
+ if (!parse_and_validate_tx_from_blob(*bd, txi.tx))
{
MERROR("Failed to parse tx from txpool");
// continue
return true;
}
- txi.tx = tx;
+ txi.tx.set_hash(txid);
txi.blob_size = bd->size();
txi.weight = meta.weight;
txi.fee = meta.fee;
@@ -881,7 +886,7 @@ namespace cryptonote
}
const crypto::key_image& k_image = kee.first;
- key_image_infos[k_image] = tx_hashes;
+ key_image_infos[k_image] = std::move(tx_hashes);
}
return true;
}
@@ -990,21 +995,23 @@ namespace cryptonote
{
struct transction_parser
{
- transction_parser(const cryptonote::blobdata &txblob, transaction &tx): txblob(txblob), tx(tx), parsed(false) {}
+ transction_parser(const cryptonote::blobdata &txblob, const crypto::hash &txid, transaction &tx): txblob(txblob), txid(txid), tx(tx), parsed(false) {}
cryptonote::transaction &operator()()
{
if (!parsed)
{
if (!parse_and_validate_tx_from_blob(txblob, tx))
throw std::runtime_error("failed to parse transaction blob");
+ tx.set_hash(txid);
parsed = true;
}
return tx;
}
const cryptonote::blobdata &txblob;
+ const crypto::hash &txid;
transaction &tx;
bool parsed;
- } lazy_tx(txblob, tx);
+ } lazy_tx(txblob, txid, tx);
//not the best implementation at this time, sorry :(
//check is ring_signature already checked ?
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h
index d7b74c06d..618b635cc 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h
@@ -131,6 +131,7 @@ namespace cryptonote
bool should_download_next_span(cryptonote_connection_context& context) const;
void drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans);
bool kick_idle_peers();
+ bool check_standby_peers();
int try_add_next_blocks(cryptonote_connection_context &context);
t_core& m_core;
@@ -143,6 +144,7 @@ namespace cryptonote
boost::mutex m_sync_lock;
block_queue m_block_queue;
epee::math_helper::once_a_time_seconds<30> m_idle_peer_kicker;
+ epee::math_helper::once_a_time_milliseconds<100> m_standby_checker;
boost::mutex m_buffer_mutex;
double get_avg_block_size();
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 1de0cde07..999ec5650 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -1210,6 +1210,7 @@ skip:
bool t_cryptonote_protocol_handler<t_core>::on_idle()
{
m_idle_peer_kicker.do_call(boost::bind(&t_cryptonote_protocol_handler<t_core>::kick_idle_peers, this));
+ m_standby_checker.do_call(boost::bind(&t_cryptonote_protocol_handler<t_core>::check_standby_peers, this));
return m_core.on_idle();
}
//------------------------------------------------------------------------------------------------------------------------
@@ -1245,6 +1246,22 @@ skip:
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
+ bool t_cryptonote_protocol_handler<t_core>::check_standby_peers()
+ {
+ m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
+ {
+ if (context.m_state == cryptonote_connection_context::state_standby)
+ {
+ LOG_PRINT_CCONTEXT_L2("requesting callback");
+ ++context.m_callback_request_count;
+ m_p2p->request_callback(context);
+ }
+ return true;
+ });
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_request_chain(int command, NOTIFY_REQUEST_CHAIN::request& arg, cryptonote_connection_context& context)
{
MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_CHAIN (" << arg.block_ids.size() << " blocks");
@@ -1338,14 +1355,13 @@ skip:
bool start_from_current_chain = false;
if (!force_next_span)
{
- bool first = true;
- while (1)
+ do
{
size_t nblocks = m_block_queue.get_num_filled_spans();
size_t size = m_block_queue.get_data_size();
if (nblocks < BLOCK_QUEUE_NBLOCKS_THRESHOLD || size < BLOCK_QUEUE_SIZE_THRESHOLD)
{
- if (!first)
+ if (context.m_state != cryptonote_connection_context::state_standby)
{
LOG_DEBUG_CC(context, "Block queue is " << nblocks << " and " << size << ", resuming");
}
@@ -1368,10 +1384,9 @@ skip:
break;
}
- if (first)
+ if (context.m_state != cryptonote_connection_context::state_standby)
{
LOG_DEBUG_CC(context, "Block queue is " << nblocks << " and " << size << ", pausing");
- first = false;
context.m_state = cryptonote_connection_context::state_standby;
}
@@ -1385,13 +1400,8 @@ skip:
return true;
}
- for (size_t n = 0; n < 50; ++n)
- {
- if (m_stopping)
- return true;
- boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
- }
- }
+ return true;
+ } while(0);
context.m_state = cryptonote_connection_context::state_synchronizing;
}
diff --git a/src/device_trezor/CMakeLists.txt b/src/device_trezor/CMakeLists.txt
index b27c843b6..7f979389a 100644
--- a/src/device_trezor/CMakeLists.txt
+++ b/src/device_trezor/CMakeLists.txt
@@ -67,14 +67,6 @@ set(trezor_private_headers)
if(DEVICE_TREZOR_READY)
message(STATUS "Trezor support enabled")
- add_definitions(-DPROTOBUF_INLINE_NOT_IN_HEADERS=0)
-
- set(TREZOR_LIBUSB_LIBRARIES "")
- if(LibUSB_COMPILE_TEST_PASSED)
- list(APPEND TREZOR_LIBUSB_LIBRARIES ${LibUSB_LIBRARIES})
- message(STATUS "Trezor compatible LibUSB found at: ${LibUSB_INCLUDE_DIRS}")
- endif()
-
monero_private_headers(device_trezor
${device_private_headers})
diff --git a/src/mnemonics/singleton.h b/src/mnemonics/singleton.h
index a15c2b9ae..d317a2d8d 100644
--- a/src/mnemonics/singleton.h
+++ b/src/mnemonics/singleton.h
@@ -50,8 +50,8 @@ namespace Language
class Singleton
{
Singleton() {}
- Singleton(Singleton &s) {}
- Singleton& operator=(const Singleton&) {}
+ Singleton(Singleton &s) = delete;
+ Singleton& operator=(const Singleton&) = delete;
public:
static T* instance()
{
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index 8930418bd..4db0a6cb7 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -197,12 +197,12 @@ namespace nodetool
const boost::program_options::variables_map& vm
);
bool idle_worker();
- bool handle_remote_peerlist(const std::list<peerlist_entry>& peerlist, time_t local_time, const epee::net_utils::connection_context_base& context);
+ bool handle_remote_peerlist(const std::vector<peerlist_entry>& peerlist, time_t local_time, const epee::net_utils::connection_context_base& context);
bool get_local_node_data(basic_node_data& node_data);
//bool get_local_handshake_data(handshake_data& hshd);
- bool merge_peerlist_with_local(const std::list<peerlist_entry>& bs);
- bool fix_time_delta(std::list<peerlist_entry>& local_peerlist, time_t local_time, int64_t& delta);
+ bool merge_peerlist_with_local(const std::vector<peerlist_entry>& bs);
+ bool fix_time_delta(std::vector<peerlist_entry>& local_peerlist, time_t local_time, int64_t& delta);
bool connections_maker();
bool peer_sync_idle_maker();
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index fbf265fc9..5b845fe15 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -1374,7 +1374,7 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::fix_time_delta(std::list<peerlist_entry>& local_peerlist, time_t local_time, int64_t& delta)
+ bool node_server<t_payload_net_handler>::fix_time_delta(std::vector<peerlist_entry>& local_peerlist, time_t local_time, int64_t& delta)
{
//fix time delta
time_t now = 0;
@@ -1394,10 +1394,10 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::handle_remote_peerlist(const std::list<peerlist_entry>& peerlist, time_t local_time, const epee::net_utils::connection_context_base& context)
+ bool node_server<t_payload_net_handler>::handle_remote_peerlist(const std::vector<peerlist_entry>& peerlist, time_t local_time, const epee::net_utils::connection_context_base& context)
{
int64_t delta = 0;
- std::list<peerlist_entry> peerlist_ = peerlist;
+ std::vector<peerlist_entry> peerlist_ = peerlist;
if(!fix_time_delta(peerlist_, local_time, delta))
return false;
LOG_DEBUG_CC(context, "REMOTE PEERLIST: TIME_DELTA: " << delta << ", remote peerlist size=" << peerlist_.size());
@@ -1779,8 +1779,8 @@ namespace nodetool
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::log_peerlist()
{
- std::list<peerlist_entry> pl_white;
- std::list<peerlist_entry> pl_gray;
+ std::vector<peerlist_entry> pl_white;
+ std::vector<peerlist_entry> pl_gray;
m_peerlist.get_peerlist_full(pl_gray, pl_white);
MINFO(ENDL << "Peerlist white:" << ENDL << print_peerlist_to_string(pl_white) << ENDL << "Peerlist gray:" << ENDL << print_peerlist_to_string(pl_gray) );
return true;
diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h
index 1d609a37e..e7aad5abe 100644
--- a/src/p2p/net_peerlist.h
+++ b/src/p2p/net_peerlist.h
@@ -68,9 +68,9 @@ namespace nodetool
bool deinit();
size_t get_white_peers_count(){CRITICAL_REGION_LOCAL(m_peerlist_lock); return m_peers_white.size();}
size_t get_gray_peers_count(){CRITICAL_REGION_LOCAL(m_peerlist_lock); return m_peers_gray.size();}
- bool merge_peerlist(const std::list<peerlist_entry>& outer_bs);
- bool get_peerlist_head(std::list<peerlist_entry>& bs_head, uint32_t depth = P2P_DEFAULT_PEERS_IN_HANDSHAKE);
- bool get_peerlist_full(std::list<peerlist_entry>& pl_gray, std::list<peerlist_entry>& pl_white);
+ bool merge_peerlist(const std::vector<peerlist_entry>& outer_bs);
+ bool get_peerlist_head(std::vector<peerlist_entry>& bs_head, uint32_t depth = P2P_DEFAULT_PEERS_IN_HANDSHAKE);
+ bool get_peerlist_full(std::vector<peerlist_entry>& pl_gray, std::vector<peerlist_entry>& pl_white);
bool get_white_peer_by_index(peerlist_entry& p, size_t i);
bool get_gray_peer_by_index(peerlist_entry& p, size_t i);
bool append_with_peer_white(const peerlist_entry& pr);
@@ -265,7 +265,7 @@ namespace nodetool
}
//--------------------------------------------------------------------------------------------------
inline
- bool peerlist_manager::merge_peerlist(const std::list<peerlist_entry>& outer_bs)
+ bool peerlist_manager::merge_peerlist(const std::vector<peerlist_entry>& outer_bs)
{
CRITICAL_REGION_LOCAL(m_peerlist_lock);
for(const peerlist_entry& be: outer_bs)
@@ -315,12 +315,13 @@ namespace nodetool
}
//--------------------------------------------------------------------------------------------------
inline
- bool peerlist_manager::get_peerlist_head(std::list<peerlist_entry>& bs_head, uint32_t depth)
+ bool peerlist_manager::get_peerlist_head(std::vector<peerlist_entry>& bs_head, uint32_t depth)
{
CRITICAL_REGION_LOCAL(m_peerlist_lock);
peers_indexed::index<by_time>::type& by_time_index=m_peers_white.get<by_time>();
uint32_t cnt = 0;
+ bs_head.reserve(depth);
for(const peers_indexed::value_type& vl: boost::adaptors::reverse(by_time_index))
{
if(!vl.last_seen)
@@ -335,16 +336,18 @@ namespace nodetool
}
//--------------------------------------------------------------------------------------------------
inline
- bool peerlist_manager::get_peerlist_full(std::list<peerlist_entry>& pl_gray, std::list<peerlist_entry>& pl_white)
+ bool peerlist_manager::get_peerlist_full(std::vector<peerlist_entry>& pl_gray, std::vector<peerlist_entry>& pl_white)
{
CRITICAL_REGION_LOCAL(m_peerlist_lock);
peers_indexed::index<by_time>::type& by_time_index_gr=m_peers_gray.get<by_time>();
+ pl_gray.resize(pl_gray.size() + by_time_index_gr.size());
for(const peers_indexed::value_type& vl: boost::adaptors::reverse(by_time_index_gr))
{
pl_gray.push_back(vl);
}
peers_indexed::index<by_time>::type& by_time_index_wt=m_peers_white.get<by_time>();
+ pl_white.resize(pl_white.size() + by_time_index_wt.size());
for(const peers_indexed::value_type& vl: boost::adaptors::reverse(by_time_index_wt))
{
pl_white.push_back(vl);
diff --git a/src/p2p/p2p_protocol_defs.h b/src/p2p/p2p_protocol_defs.h
index e793e19b6..bb9d2635c 100644
--- a/src/p2p/p2p_protocol_defs.h
+++ b/src/p2p/p2p_protocol_defs.h
@@ -114,7 +114,7 @@ namespace nodetool
#pragma pack(pop)
inline
- std::string print_peerlist_to_string(const std::list<peerlist_entry>& pl)
+ std::string print_peerlist_to_string(const std::vector<peerlist_entry>& pl)
{
time_t now_time = 0;
time(&now_time);
@@ -189,7 +189,7 @@ namespace nodetool
{
basic_node_data node_data;
t_playload_type payload_data;
- std::list<peerlist_entry> local_peerlist_new;
+ std::vector<peerlist_entry> local_peerlist_new;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(node_data)
@@ -198,7 +198,7 @@ namespace nodetool
{
// saving: save both, so old and new peers can understand it
KV_SERIALIZE(local_peerlist_new)
- std::list<peerlist_entry_base<network_address_old>> local_peerlist;
+ std::vector<peerlist_entry_base<network_address_old>> local_peerlist;
for (const auto &p: this_ref.local_peerlist_new)
{
if (p.adr.get_type_id() == epee::net_utils::ipv4_network_address::ID)
@@ -217,7 +217,7 @@ namespace nodetool
// loading: load old list only if there is no new one
if (!epee::serialization::selector<is_store>::serialize(this_ref.local_peerlist_new, stg, hparent_section, "local_peerlist_new"))
{
- std::list<peerlist_entry_base<network_address_old>> local_peerlist;
+ std::vector<peerlist_entry_base<network_address_old>> local_peerlist;
epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist");
for (const auto &p: local_peerlist)
((response&)this_ref).local_peerlist_new.push_back(peerlist_entry({epee::net_utils::ipv4_network_address(p.adr.ip, p.adr.port), p.id, p.last_seen}));
@@ -248,7 +248,7 @@ namespace nodetool
{
uint64_t local_time;
t_playload_type payload_data;
- std::list<peerlist_entry> local_peerlist_new;
+ std::vector<peerlist_entry> local_peerlist_new;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(local_time)
@@ -257,7 +257,7 @@ namespace nodetool
{
// saving: save both, so old and new peers can understand it
KV_SERIALIZE(local_peerlist_new)
- std::list<peerlist_entry_base<network_address_old>> local_peerlist;
+ std::vector<peerlist_entry_base<network_address_old>> local_peerlist;
for (const auto &p: this_ref.local_peerlist_new)
{
if (p.adr.get_type_id() == epee::net_utils::ipv4_network_address::ID)
@@ -276,7 +276,7 @@ namespace nodetool
// loading: load old list only if there is no new one
if (!epee::serialization::selector<is_store>::serialize(this_ref.local_peerlist_new, stg, hparent_section, "local_peerlist_new"))
{
- std::list<peerlist_entry_base<network_address_old>> local_peerlist;
+ std::vector<peerlist_entry_base<network_address_old>> local_peerlist;
epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist");
for (const auto &p: local_peerlist)
((response&)this_ref).local_peerlist_new.push_back(peerlist_entry({epee::net_utils::ipv4_network_address(p.adr.ip, p.adr.port), p.id, p.last_seen}));
@@ -389,9 +389,9 @@ namespace nodetool
struct response
{
- std::list<peerlist_entry> local_peerlist_white;
- std::list<peerlist_entry> local_peerlist_gray;
- std::list<connection_entry> connections_list;
+ std::vector<peerlist_entry> local_peerlist_white;
+ std::vector<peerlist_entry> local_peerlist_gray;
+ std::vector<connection_entry> connections_list;
peerid_type my_id;
uint64_t local_time;
BEGIN_KV_SERIALIZE_MAP()
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 3851af3c8..0aa25bda7 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -857,11 +857,11 @@ namespace cryptonote
bool core_rpc_server::on_get_peer_list(const COMMAND_RPC_GET_PEER_LIST::request& req, COMMAND_RPC_GET_PEER_LIST::response& res)
{
PERF_TIMER(on_get_peer_list);
- std::list<nodetool::peerlist_entry> white_list;
- std::list<nodetool::peerlist_entry> gray_list;
+ std::vector<nodetool::peerlist_entry> white_list;
+ std::vector<nodetool::peerlist_entry> gray_list;
m_p2p.get_peerlist_manager().get_peerlist_full(gray_list, white_list);
-
+ res.white_list.reserve(white_list.size());
for (auto & entry : white_list)
{
if (entry.adr.get_type_id() == epee::net_utils::ipv4_network_address::ID)
@@ -871,6 +871,7 @@ namespace cryptonote
res.white_list.emplace_back(entry.id, entry.adr.str(), entry.last_seen);
}
+ res.gray_list.reserve(gray_list.size());
for (auto & entry : gray_list)
{
if (entry.adr.get_type_id() == epee::net_utils::ipv4_network_address::ID)
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 281702774..bdb6d2bfe 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -111,6 +111,8 @@ typedef cryptonote::simple_wallet sw;
#define SCOPED_WALLET_UNLOCK() SCOPED_WALLET_UNLOCK_ON_BAD_PASSWORD(return true;)
+#define PRINT_USAGE(usage_help) fail_msg_writer() << boost::format(tr("usage: %s")) % usage_help;
+
enum TransferType {
Transfer,
TransferLocked,
@@ -141,6 +143,93 @@ namespace
const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""};
+ const char* USAGE_START_MINING("start_mining [<number_of_threads>] [bg_mining] [ignore_battery]");
+ const char* USAGE_SET_DAEMON("set_daemon <host>[:<port>] [trusted|untrusted]");
+ const char* USAGE_SHOW_BALANCE("balance [detail]");
+ const char* USAGE_INCOMING_TRANSFERS("incoming_transfers [available|unavailable] [verbose] [uses] [index=<N1>[,<N2>[,...]]]");
+ const char* USAGE_PAYMENTS("payments <PID_1> [<PID_2> ... <PID_N>]");
+ const char* USAGE_PAYMENT_ID("payment_id");
+ const char* USAGE_TRANSFER("transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <address> <amount>) [<payment_id>]");
+ const char* USAGE_LOCKED_TRANSFER("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <addr> <amount>) <lockblocks> [<payment_id>]");
+ const char* USAGE_LOCKED_SWEEP_ALL("locked_sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <lockblocks> [<payment_id>]");
+ const char* USAGE_SWEEP_ALL("sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id>]");
+ const char* USAGE_SWEEP_BELOW("sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id>]");
+ const char* USAGE_SWEEP_SINGLE("sweep_single [<priority>] [<ring_size>] [outputs=<N>] <key_image> <address> [<payment_id>]");
+ const char* USAGE_DONATE("donate [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <amount> [<payment_id>]");
+ const char* USAGE_SIGN_TRANSFER("sign_transfer [export_raw]");
+ const char* USAGE_SET_LOG("set_log <level>|{+,-,}<categories>");
+ const char* USAGE_ACCOUNT("account\n"
+ " account new <label text with white spaces allowed>\n"
+ " account switch <index> \n"
+ " account label <index> <label text with white spaces allowed>\n"
+ " account tag <tag_name> <account_index_1> [<account_index_2> ...]\n"
+ " account untag <account_index_1> [<account_index_2> ...]\n"
+ " account tag_description <tag_name> <description>");
+ const char* USAGE_ADDRESS("address [ new <label text with white spaces allowed> | all | <index_min> [<index_max>] | label <index> <label text with white spaces allowed>]");
+ const char* USAGE_INTEGRATED_ADDRESS("integrated_address [<payment_id> | <address>]");
+ const char* USAGE_ADDRESS_BOOK("address_book [(add ((<address> [pid <id>])|<integrated address>) [<description possibly with whitespaces>])|(delete <index>)]");
+ const char* USAGE_SET_VARIABLE("set <option> [<value>]");
+ const char* USAGE_GET_TX_KEY("get_tx_key <txid>");
+ const char* USAGE_SET_TX_KEY("set_tx_key <txid> <tx_key>");
+ const char* USAGE_CHECK_TX_KEY("check_tx_key <txid> <txkey> <address>");
+ const char* USAGE_GET_TX_PROOF("get_tx_proof <txid> <address> [<message>]");
+ const char* USAGE_CHECK_TX_PROOF("check_tx_proof <txid> <address> <signature_file> [<message>]");
+ const char* USAGE_GET_SPEND_PROOF("get_spend_proof <txid> [<message>]");
+ const char* USAGE_CHECK_SPEND_PROOF("check_spend_proof <txid> <signature_file> [<message>]");
+ const char* USAGE_GET_RESERVE_PROOF("get_reserve_proof (all|<amount>) [<message>]");
+ const char* USAGE_CHECK_RESERVE_PROOF("check_reserve_proof <address> <signature_file> [<message>]");
+ const char* USAGE_SHOW_TRANSFERS("show_transfers [in|out|pending|failed|pool|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]");
+ const char* USAGE_UNSPENT_OUTPUTS("unspent_outputs [index=<N1>[,<N2>,...]] [<min_amount> [<max_amount>]]");
+ const char* USAGE_RESCAN_BC("rescan_bc [hard]");
+ const char* USAGE_SET_TX_NOTE("set_tx_note <txid> [free text note]");
+ const char* USAGE_GET_TX_NOTE("get_tx_note <txid>");
+ const char* USAGE_GET_DESCRIPTION("get_description");
+ const char* USAGE_SET_DESCRIPTION("set_description [free text note]");
+ const char* USAGE_SIGN("sign <filename>");
+ const char* USAGE_VERIFY("verify <filename> <address> <signature>");
+ const char* USAGE_EXPORT_KEY_IMAGES("export_key_images <filename>");
+ const char* USAGE_IMPORT_KEY_IMAGES("import_key_images <filename>");
+ const char* USAGE_HW_KEY_IMAGES_SYNC("hw_key_images_sync");
+ const char* USAGE_HW_RECONNECT("hw_reconnect");
+ const char* USAGE_EXPORT_OUTPUTS("export_outputs <filename>");
+ const char* USAGE_IMPORT_OUTPUTS("import_outputs <filename>");
+ const char* USAGE_SHOW_TRANSFER("show_transfer <txid>");
+ const char* USAGE_MAKE_MULTISIG("make_multisig <threshold> <string1> [<string>...]");
+ const char* USAGE_FINALIZE_MULTISIG("finalize_multisig <string> [<string>...]");
+ const char* USAGE_EXCHANGE_MULTISIG_KEYS("exchange_multisig_keys <string> [<string>...]");
+ const char* USAGE_EXPORT_MULTISIG_INFO("export_multisig_info <filename>");
+ const char* USAGE_IMPORT_MULTISIG_INFO("import_multisig_info <filename> [<filename>...]");
+ const char* USAGE_SIGN_MULTISIG("sign_multisig <filename>");
+ const char* USAGE_SUBMIT_MULTISIG("submit_multisig <filename>");
+ const char* USAGE_EXPORT_RAW_MULTISIG_TX("export_raw_multisig_tx <filename>");
+ const char* USAGE_MMS("mms [<subcommand> [<subcommand_parameters>]]");
+ const char* USAGE_MMS_INIT("mms init <required_signers>/<authorized_signers> <own_label> <own_transport_address>");
+ const char* USAGE_MMS_INFO("mms info");
+ const char* USAGE_MMS_SIGNER("mms signer [<number> <label> [<transport_address> [<monero_address>]]]");
+ const char* USAGE_MMS_LIST("mms list");
+ const char* USAGE_MMS_NEXT("mms next [sync]");
+ const char* USAGE_MMS_SYNC("mms sync");
+ const char* USAGE_MMS_TRANSFER("mms transfer <transfer_command_arguments>");
+ const char* USAGE_MMS_DELETE("mms delete (<message_id> | all)");
+ const char* USAGE_MMS_SEND("mms send [<message_id>]");
+ const char* USAGE_MMS_RECEIVE("mms receive");
+ const char* USAGE_MMS_EXPORT("mms export <message_id>");
+ const char* USAGE_MMS_NOTE("mms note [<label> <text>]");
+ const char* USAGE_MMS_SHOW("mms show <message_id>");
+ const char* USAGE_MMS_SET("mms set <option_name> [<option_value>]");
+ const char* USAGE_MMS_SEND_SIGNER_CONFIG("mms send_signer_config");
+ const char* USAGE_MMS_START_AUTO_CONFIG("mms start_auto_config [<label> <label> ...]");
+ const char* USAGE_MMS_STOP_AUTO_CONFIG("mms stop_auto_config");
+ const char* USAGE_MMS_AUTO_CONFIG("mms auto_config <auto_config_token>");
+ const char* USAGE_PRINT_RING("print_ring <key_image> | <txid>");
+ const char* USAGE_SET_RING("set_ring <filename> | ( <key_image> absolute|relative <index> [<index>...] )");
+ const char* USAGE_SAVE_KNOWN_RINGS("save_known_rings");
+ const char* USAGE_MARK_OUTPUT_SPENT("mark_output_spent <amount>/<offset> | <filename> [add]");
+ const char* USAGE_MARK_OUTPUT_UNSPENT("mark_output_unspent <amount>/<offset>");
+ const char* USAGE_IS_OUTPUT_SPENT("is_output_spent <amount>/<offset>");
+ const char* USAGE_VERSION("version");
+ const char* USAGE_HELP("help [<command>]");
+
std::string input_line(const std::string& prompt)
{
#ifdef HAVE_READLINE
@@ -774,7 +863,7 @@ bool simple_wallet::payment_id(const std::vector<std::string> &args/* = std::vec
crypto::hash payment_id;
if (args.size() > 0)
{
- fail_msg_writer() << tr("usage: payment_id");
+ PRINT_USAGE(USAGE_PAYMENT_ID);
return true;
}
payment_id = crypto::rand<crypto::hash>();
@@ -914,7 +1003,7 @@ bool simple_wallet::make_multisig_main(const std::vector<std::string> &args, boo
if (args.size() < 2)
{
- fail_msg_writer() << tr("usage: make_multisig <threshold> <multisiginfo1> [<multisiginfo2>...]");
+ PRINT_USAGE(USAGE_MAKE_MULTISIG);
return false;
}
@@ -1001,7 +1090,7 @@ bool simple_wallet::finalize_multisig(const std::vector<std::string> &args)
if (args.size() < 2)
{
- fail_msg_writer() << tr("usage: finalize_multisig <multisiginfo1> [<multisiginfo2>...]");
+ PRINT_USAGE(USAGE_FINALIZE_MULTISIG);
return true;
}
@@ -1055,7 +1144,7 @@ bool simple_wallet::exchange_multisig_keys_main(const std::vector<std::string> &
if (args.size() < 2)
{
- fail_msg_writer() << tr("usage: exchange_multisig_keys <multisiginfo1> [<multisiginfo2>...]");
+ PRINT_USAGE(USAGE_EXCHANGE_MULTISIG_KEYS);
return false;
}
@@ -1113,7 +1202,7 @@ bool simple_wallet::export_multisig_main(const std::vector<std::string> &args, b
}
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: export_multisig_info <filename>");
+ PRINT_USAGE(USAGE_EXPORT_MULTISIG_INFO);
return false;
}
@@ -1179,7 +1268,7 @@ bool simple_wallet::import_multisig_main(const std::vector<std::string> &args, b
}
if (args.size() < threshold - 1)
{
- fail_msg_writer() << tr("usage: import_multisig_info <filename1> [<filename2>...] - one for each other participant");
+ PRINT_USAGE(USAGE_IMPORT_MULTISIG_INFO);
return false;
}
@@ -1273,7 +1362,7 @@ bool simple_wallet::sign_multisig_main(const std::vector<std::string> &args, boo
}
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: sign_multisig <filename>");
+ PRINT_USAGE(USAGE_SIGN_MULTISIG);
return false;
}
@@ -1389,7 +1478,7 @@ bool simple_wallet::submit_multisig_main(const std::vector<std::string> &args, b
}
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: submit_multisig <filename>");
+ PRINT_USAGE(USAGE_SUBMIT_MULTISIG);
return false;
}
@@ -1470,7 +1559,7 @@ bool simple_wallet::export_raw_multisig(const std::vector<std::string> &args)
}
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: export_raw_multisig <filename>");
+ PRINT_USAGE(USAGE_EXPORT_RAW_MULTISIG_TX);
return true;
}
@@ -1533,7 +1622,7 @@ bool simple_wallet::print_ring(const std::vector<std::string> &args)
crypto::hash txid;
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: print_ring <key_image> | <txid>");
+ PRINT_USAGE(USAGE_PRINT_RING);
return true;
}
@@ -1690,7 +1779,7 @@ bool simple_wallet::set_ring(const std::vector<std::string> &args)
if (args.size() < 3)
{
- fail_msg_writer() << tr("usage: set_ring <filename> | ( <key_image> absolute|relative <index> [<index>...] )");
+ PRINT_USAGE(USAGE_SET_RING);
return true;
}
@@ -1765,7 +1854,7 @@ bool simple_wallet::blackball(const std::vector<std::string> &args)
uint64_t amount = std::numeric_limits<uint64_t>::max(), offset, num_offsets;
if (args.size() == 0)
{
- fail_msg_writer() << tr("usage: mark_output_spent <amount>/<offset> | <filename> [add]");
+ PRINT_USAGE(USAGE_MARK_OUTPUT_SPENT);
return true;
}
@@ -1854,7 +1943,7 @@ bool simple_wallet::unblackball(const std::vector<std::string> &args)
std::pair<uint64_t, uint64_t> output;
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: mark_output_unspent <amount>/<offset>");
+ PRINT_USAGE(USAGE_MARK_OUTPUT_UNSPENT);
return true;
}
@@ -1881,7 +1970,7 @@ bool simple_wallet::blackballed(const std::vector<std::string> &args)
std::pair<uint64_t, uint64_t> output;
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: is_output_spent <amount>/<offset>");
+ PRINT_USAGE(USAGE_IS_OUTPUT_SPENT);
return true;
}
@@ -2399,6 +2488,19 @@ bool simple_wallet::set_ignore_fractional_outputs(const std::vector<std::string>
return true;
}
+bool simple_wallet::set_track_uses(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
+{
+ const auto pwd_container = get_and_verify_password();
+ if (pwd_container)
+ {
+ parse_bool_and_use(args[1], [&](bool r) {
+ m_wallet->track_uses(r);
+ m_wallet->rewrite(m_wallet_file, pwd_container->password());
+ });
+ }
+ return true;
+}
+
bool simple_wallet::set_device_name(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
const auto pwd_container = get_and_verify_password();
@@ -2456,14 +2558,14 @@ simple_wallet::simple_wallet()
{
m_cmd_binder.set_handler("start_mining",
boost::bind(&simple_wallet::start_mining, this, _1),
- tr("start_mining [<number_of_threads>] [bg_mining] [ignore_battery]"),
+ tr(USAGE_START_MINING),
tr("Start mining in the daemon (bg_mining and ignore_battery are optional booleans)."));
m_cmd_binder.set_handler("stop_mining",
boost::bind(&simple_wallet::stop_mining, this, _1),
tr("Stop mining in the daemon."));
m_cmd_binder.set_handler("set_daemon",
boost::bind(&simple_wallet::set_daemon, this, _1),
- tr("set_daemon <host>[:<port>] [trusted|untrusted]"),
+ tr(USAGE_SET_DAEMON),
tr("Set another daemon to connect to."));
m_cmd_binder.set_handler("save_bc",
boost::bind(&simple_wallet::save_bc, this, _1),
@@ -2473,70 +2575,64 @@ simple_wallet::simple_wallet()
tr("Synchronize the transactions and balance."));
m_cmd_binder.set_handler("balance",
boost::bind(&simple_wallet::show_balance, this, _1),
- tr("balance [detail]"),
+ tr(USAGE_SHOW_BALANCE),
tr("Show the wallet's balance of the currently selected account."));
m_cmd_binder.set_handler("incoming_transfers",
boost::bind(&simple_wallet::show_incoming_transfers, this, _1),
- tr("incoming_transfers [available|unavailable] [verbose] [index=<N1>[,<N2>[,...]]]"),
+ tr(USAGE_INCOMING_TRANSFERS),
tr("Show the incoming transfers, all or filtered by availability and address index.\n\n"
"Output format:\n"
"Amount, Spent(\"T\"|\"F\"), \"locked\"|\"unlocked\", RingCT, Global Index, Transaction Hash, Address Index, [Public Key, Key Image] "));
m_cmd_binder.set_handler("payments",
boost::bind(&simple_wallet::show_payments, this, _1),
- tr("payments <PID_1> [<PID_2> ... <PID_N>]"),
+ tr(USAGE_PAYMENTS),
tr("Show the payments for the given payment IDs."));
m_cmd_binder.set_handler("bc_height",
boost::bind(&simple_wallet::show_blockchain_height, this, _1),
tr("Show the blockchain height."));
m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer, this, _1),
- tr("transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <address> <amount>) [<payment_id>]"),
+ tr(USAGE_TRANSFER),
tr("Transfer <amount> to <address>. If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding URI_2 or <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
m_cmd_binder.set_handler("locked_transfer",
boost::bind(&simple_wallet::locked_transfer, this, _1),
- tr("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <addr> <amount>) <lockblocks> [<payment_id>]"),
+ tr(USAGE_LOCKED_TRANSFER),
tr("Transfer <amount> to <address> and lock it for <lockblocks> (max. 1000000). If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding URI_2 or <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
m_cmd_binder.set_handler("locked_sweep_all",
boost::bind(&simple_wallet::locked_sweep_all, this, _1),
- tr("locked_sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <lockblocks> [<payment_id>]"),
+ tr(USAGE_LOCKED_SWEEP_ALL),
tr("Send all unlocked balance to an address and lock it for <lockblocks> (max. 1000000). If the parameter \"index<N1>[,<N2>,...]\" is specified, the wallet sweeps outputs received by those address indices. If omitted, the wallet randomly chooses an address index to be used. <priority> is the priority of the sweep. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability."));
m_cmd_binder.set_handler("sweep_unmixable",
boost::bind(&simple_wallet::sweep_unmixable, this, _1),
tr("Send all unmixable outputs to yourself with ring_size 1"));
m_cmd_binder.set_handler("sweep_all", boost::bind(&simple_wallet::sweep_all, this, _1),
- tr("sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id>]"),
+ tr(USAGE_SWEEP_ALL),
tr("Send all unlocked balance to an address. If the parameter \"index<N1>[,<N2>,...]\" is specified, the wallet sweeps outputs received by those address indices. If omitted, the wallet randomly chooses an address index to be used. If the parameter \"outputs=<N>\" is specified and N > 0, wallet splits the transaction into N even outputs."));
m_cmd_binder.set_handler("sweep_below",
boost::bind(&simple_wallet::sweep_below, this, _1),
- tr("sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id>]"),
+ tr(USAGE_SWEEP_BELOW),
tr("Send all unlocked outputs below the threshold to an address."));
m_cmd_binder.set_handler("sweep_single",
boost::bind(&simple_wallet::sweep_single, this, _1),
- tr("sweep_single [<priority>] [<ring_size>] [outputs=<N>] <key_image> <address> [<payment_id>]"),
+ tr(USAGE_SWEEP_SINGLE),
tr("Send a single output of the given key image to an address without change."));
m_cmd_binder.set_handler("donate",
boost::bind(&simple_wallet::donate, this, _1),
- tr("donate [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <amount> [<payment_id>]"),
+ tr(USAGE_DONATE),
tr("Donate <amount> to the development team (donate.getmonero.org)."));
m_cmd_binder.set_handler("sign_transfer",
boost::bind(&simple_wallet::sign_transfer, this, _1),
- tr("sign_transfer [export_raw]"),
+ tr(USAGE_SIGN_TRANSFER),
tr("Sign a transaction from a file. If the parameter \"export_raw\" is specified, transaction raw hex data suitable for the daemon RPC /sendrawtransaction is exported."));
m_cmd_binder.set_handler("submit_transfer",
boost::bind(&simple_wallet::submit_transfer, this, _1),
tr("Submit a signed transaction from a file."));
m_cmd_binder.set_handler("set_log",
boost::bind(&simple_wallet::set_log, this, _1),
- tr("set_log <level>|{+,-,}<categories>"),
+ tr(USAGE_SET_LOG),
tr("Change the current log detail (level must be <0-4>)."));
m_cmd_binder.set_handler("account",
boost::bind(&simple_wallet::account, this, _1),
- tr("account\n"
- " account new <label text with white spaces allowed>\n"
- " account switch <index> \n"
- " account label <index> <label text with white spaces allowed>\n"
- " account tag <tag_name> <account_index_1> [<account_index_2> ...]\n"
- " account untag <account_index_1> [<account_index_2> ...]\n"
- " account tag_description <tag_name> <description>"),
+ tr(USAGE_ACCOUNT),
tr("If no arguments are specified, the wallet shows all the existing accounts along with their balances.\n"
"If the \"new\" argument is specified, the wallet creates a new account with its label initialized by the provided label text (which can be empty).\n"
"If the \"switch\" argument is specified, the wallet switches to the account specified by <index>.\n"
@@ -2546,15 +2642,15 @@ simple_wallet::simple_wallet()
"If the \"tag_description\" argument is specified, the tag <tag_name> is assigned an arbitrary text <description>."));
m_cmd_binder.set_handler("address",
boost::bind(&simple_wallet::print_address, this, _1),
- tr("address [ new <label text with white spaces allowed> | all | <index_min> [<index_max>] | label <index> <label text with white spaces allowed>]"),
+ tr(USAGE_ADDRESS),
tr("If no arguments are specified or <index> is specified, the wallet shows the default or specified address. If \"all\" is specified, the wallet shows all the existing addresses in the currently selected account. If \"new \" is specified, the wallet creates a new address with the provided label text (which can be empty). If \"label\" is specified, the wallet sets the label of the address specified by <index> to the provided label text."));
m_cmd_binder.set_handler("integrated_address",
boost::bind(&simple_wallet::print_integrated_address, this, _1),
- tr("integrated_address [<payment_id> | <address>]"),
+ tr(USAGE_INTEGRATED_ADDRESS),
tr("Encode a payment ID into an integrated address for the current wallet public address (no argument uses a random payment ID), or decode an integrated address to standard address and payment ID"));
m_cmd_binder.set_handler("address_book",
boost::bind(&simple_wallet::address_book, this, _1),
- tr("address_book [(add ((<address> [pid <id>])|<integrated address>) [<description possibly with whitespaces>])|(delete <index>)]"),
+ tr(USAGE_ADDRESS_BOOK),
tr("Print all entries in the address book, optionally adding/deleting an entry to/from it."));
m_cmd_binder.set_handler("save",
boost::bind(&simple_wallet::save, this, _1),
@@ -2573,7 +2669,7 @@ simple_wallet::simple_wallet()
tr("Display the Electrum-style mnemonic seed"));
m_cmd_binder.set_handler("set",
boost::bind(&simple_wallet::set_variable, this, _1),
- tr("set <option> [<value>]"),
+ tr(USAGE_SET_VARIABLE),
tr("Available options:\n "
"seed language\n "
" Set the wallet's seed language.\n "
@@ -2626,45 +2722,45 @@ simple_wallet::simple_wallet()
tr("Rescan the blockchain for spent outputs."));
m_cmd_binder.set_handler("get_tx_key",
boost::bind(&simple_wallet::get_tx_key, this, _1),
- tr("get_tx_key <txid>"),
+ tr(USAGE_GET_TX_KEY),
tr("Get the transaction key (r) for a given <txid>."));
m_cmd_binder.set_handler("set_tx_key",
boost::bind(&simple_wallet::set_tx_key, this, _1),
- tr("set_tx_key <txid> <tx_key>"),
+ tr(USAGE_SET_TX_KEY),
tr("Set the transaction key (r) for a given <txid> in case the tx was made by some other device or 3rd party wallet."));
m_cmd_binder.set_handler("check_tx_key",
boost::bind(&simple_wallet::check_tx_key, this, _1),
- tr("check_tx_key <txid> <txkey> <address>"),
+ tr(USAGE_CHECK_TX_KEY),
tr("Check the amount going to <address> in <txid>."));
m_cmd_binder.set_handler("get_tx_proof",
boost::bind(&simple_wallet::get_tx_proof, this, _1),
- tr("get_tx_proof <txid> <address> [<message>]"),
+ tr(USAGE_GET_TX_PROOF),
tr("Generate a signature proving funds sent to <address> in <txid>, optionally with a challenge string <message>, using either the transaction secret key (when <address> is not your wallet's address) or the view secret key (otherwise), which does not disclose the secret key."));
m_cmd_binder.set_handler("check_tx_proof",
boost::bind(&simple_wallet::check_tx_proof, this, _1),
- tr("check_tx_proof <txid> <address> <signature_file> [<message>]"),
+ tr(USAGE_CHECK_TX_PROOF),
tr("Check the proof for funds going to <address> in <txid> with the challenge string <message> if any."));
m_cmd_binder.set_handler("get_spend_proof",
boost::bind(&simple_wallet::get_spend_proof, this, _1),
- tr("get_spend_proof <txid> [<message>]"),
+ tr(USAGE_GET_SPEND_PROOF),
tr("Generate a signature proving that you generated <txid> using the spend secret key, optionally with a challenge string <message>."));
m_cmd_binder.set_handler("check_spend_proof",
boost::bind(&simple_wallet::check_spend_proof, this, _1),
- tr("check_spend_proof <txid> <signature_file> [<message>]"),
+ tr(USAGE_CHECK_SPEND_PROOF),
tr("Check a signature proving that the signer generated <txid>, optionally with a challenge string <message>."));
m_cmd_binder.set_handler("get_reserve_proof",
boost::bind(&simple_wallet::get_reserve_proof, this, _1),
- tr("get_reserve_proof (all|<amount>) [<message>]"),
+ tr(USAGE_GET_RESERVE_PROOF),
tr("Generate a signature proving that you own at least this much, optionally with a challenge string <message>.\n"
"If 'all' is specified, you prove the entire sum of all of your existing accounts' balances.\n"
"Otherwise, you prove the reserve of the smallest possible amount above <amount> available in your current account."));
m_cmd_binder.set_handler("check_reserve_proof",
boost::bind(&simple_wallet::check_reserve_proof, this, _1),
- tr("check_reserve_proof <address> <signature_file> [<message>]"),
+ tr(USAGE_CHECK_RESERVE_PROOF),
tr("Check a signature proving that the owner of <address> holds at least this much, optionally with a challenge string <message>."));
m_cmd_binder.set_handler("show_transfers",
boost::bind(&simple_wallet::show_transfers, this, _1),
- tr("show_transfers [in|out|pending|failed|pool|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]"),
+ tr(USAGE_SHOW_TRANSFERS),
// Seemingly broken formatting to compensate for the backslash before the quotes.
tr("Show the incoming/outgoing transfers within an optional height range.\n\n"
"Output format:\n"
@@ -2680,26 +2776,27 @@ simple_wallet::simple_wallet()
tr("Export to CSV the incoming/outgoing transfers within an optional height range."));
m_cmd_binder.set_handler("unspent_outputs",
boost::bind(&simple_wallet::unspent_outputs, this, _1),
- tr("unspent_outputs [index=<N1>[,<N2>,...]] [<min_amount> [<max_amount>]]"),
+ tr(USAGE_UNSPENT_OUTPUTS),
tr("Show the unspent outputs of a specified address within an optional amount range."));
m_cmd_binder.set_handler("rescan_bc",
boost::bind(&simple_wallet::rescan_blockchain, this, _1),
- tr("rescan_bc [hard]"),
+ tr(USAGE_RESCAN_BC),
tr("Rescan the blockchain from scratch, losing any information which can not be recovered from the blockchain itself."));
m_cmd_binder.set_handler("set_tx_note",
boost::bind(&simple_wallet::set_tx_note, this, _1),
- tr("set_tx_note <txid> [free text note]"),
+ tr(USAGE_SET_TX_NOTE),
tr("Set an arbitrary string note for a <txid>."));
m_cmd_binder.set_handler("get_tx_note",
boost::bind(&simple_wallet::get_tx_note, this, _1),
- tr("get_tx_note <txid>"),
+ tr(USAGE_GET_TX_NOTE),
tr("Get a string note for a txid."));
m_cmd_binder.set_handler("set_description",
boost::bind(&simple_wallet::set_description, this, _1),
- tr("set_description [free text note]"),
+ tr(USAGE_SET_DESCRIPTION),
tr("Set an arbitrary description for the wallet."));
m_cmd_binder.set_handler("get_description",
boost::bind(&simple_wallet::get_description, this, _1),
+ tr(USAGE_GET_DESCRIPTION),
tr("Get the description of the wallet."));
m_cmd_binder.set_handler("status",
boost::bind(&simple_wallet::status, this, _1),
@@ -2709,45 +2806,46 @@ simple_wallet::simple_wallet()
tr("Show the wallet's information."));
m_cmd_binder.set_handler("sign",
boost::bind(&simple_wallet::sign, this, _1),
- tr("sign <file>"),
+ tr(USAGE_SIGN),
tr("Sign the contents of a file."));
m_cmd_binder.set_handler("verify",
boost::bind(&simple_wallet::verify, this, _1),
- tr("verify <filename> <address> <signature>"),
+ tr(USAGE_VERIFY),
tr("Verify a signature on the contents of a file."));
m_cmd_binder.set_handler("export_key_images",
boost::bind(&simple_wallet::export_key_images, this, _1),
- tr("export_key_images <file>"),
- tr("Export a signed set of key images to a <file>."));
+ tr(USAGE_EXPORT_KEY_IMAGES),
+ tr("Export a signed set of key images to a <filename>."));
m_cmd_binder.set_handler("import_key_images",
boost::bind(&simple_wallet::import_key_images, this, _1),
- tr("import_key_images <file>"),
+ tr(USAGE_IMPORT_KEY_IMAGES),
tr("Import a signed key images list and verify their spent status."));
m_cmd_binder.set_handler("hw_key_images_sync",
boost::bind(&simple_wallet::hw_key_images_sync, this, _1),
- tr("hw_key_images_sync"),
+ tr(USAGE_HW_KEY_IMAGES_SYNC),
tr("Synchronizes key images with the hw wallet."));
m_cmd_binder.set_handler("hw_reconnect",
boost::bind(&simple_wallet::hw_reconnect, this, _1),
- tr("hw_reconnect"),
+ tr(USAGE_HW_RECONNECT),
tr("Attempts to reconnect HW wallet."));
m_cmd_binder.set_handler("export_outputs",
boost::bind(&simple_wallet::export_outputs, this, _1),
- tr("export_outputs <file>"),
+ tr(USAGE_EXPORT_OUTPUTS),
tr("Export a set of outputs owned by this wallet."));
m_cmd_binder.set_handler("import_outputs",
boost::bind(&simple_wallet::import_outputs, this, _1),
- tr("import_outputs <file>"),
+ tr(USAGE_IMPORT_OUTPUTS),
tr("Import a set of outputs owned by this wallet."));
m_cmd_binder.set_handler("show_transfer",
boost::bind(&simple_wallet::show_transfer, this, _1),
- tr("show_transfer <txid>"),
+ tr(USAGE_SHOW_TRANSFER),
tr("Show information about a transfer to/from this address."));
m_cmd_binder.set_handler("password",
boost::bind(&simple_wallet::change_password, this, _1),
tr("Change the wallet's password."));
m_cmd_binder.set_handler("payment_id",
boost::bind(&simple_wallet::payment_id, this, _1),
+ tr(USAGE_PAYMENT_ID),
tr("Generate a new random full size payment id. These will be unencrypted on the blockchain, see integrated_address for encrypted short payment ids."));
m_cmd_binder.set_handler("fee",
boost::bind(&simple_wallet::print_fee_info, this, _1),
@@ -2755,39 +2853,39 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("prepare_multisig", boost::bind(&simple_wallet::prepare_multisig, this, _1),
tr("Export data needed to create a multisig wallet"));
m_cmd_binder.set_handler("make_multisig", boost::bind(&simple_wallet::make_multisig, this, _1),
- tr("make_multisig <threshold> <string1> [<string>...]"),
+ tr(USAGE_MAKE_MULTISIG),
tr("Turn this wallet into a multisig wallet"));
m_cmd_binder.set_handler("finalize_multisig",
boost::bind(&simple_wallet::finalize_multisig, this, _1),
- tr("finalize_multisig <string> [<string>...]"),
+ tr(USAGE_FINALIZE_MULTISIG),
tr("Turn this wallet into a multisig wallet, extra step for N-1/N wallets"));
m_cmd_binder.set_handler("exchange_multisig_keys",
boost::bind(&simple_wallet::exchange_multisig_keys, this, _1),
- tr("exchange_multisig_keys <string> [<string>...]"),
+ tr(USAGE_EXCHANGE_MULTISIG_KEYS),
tr("Performs extra multisig keys exchange rounds. Needed for arbitrary M/N multisig wallets"));
m_cmd_binder.set_handler("export_multisig_info",
boost::bind(&simple_wallet::export_multisig, this, _1),
- tr("export_multisig_info <filename>"),
+ tr(USAGE_EXPORT_MULTISIG_INFO),
tr("Export multisig info for other participants"));
m_cmd_binder.set_handler("import_multisig_info",
boost::bind(&simple_wallet::import_multisig, this, _1),
- tr("import_multisig_info <filename> [<filename>...]"),
+ tr(USAGE_IMPORT_MULTISIG_INFO),
tr("Import multisig info from other participants"));
m_cmd_binder.set_handler("sign_multisig",
boost::bind(&simple_wallet::sign_multisig, this, _1),
- tr("sign_multisig <filename>"),
+ tr(USAGE_SIGN_MULTISIG),
tr("Sign a multisig transaction from a file"));
m_cmd_binder.set_handler("submit_multisig",
boost::bind(&simple_wallet::submit_multisig, this, _1),
- tr("submit_multisig <filename>"),
+ tr(USAGE_SUBMIT_MULTISIG),
tr("Submit a signed multisig transaction from a file"));
m_cmd_binder.set_handler("export_raw_multisig_tx",
boost::bind(&simple_wallet::export_raw_multisig, this, _1),
- tr("export_raw_multisig_tx <filename>"),
+ tr(USAGE_EXPORT_RAW_MULTISIG_TX),
tr("Export a signed multisig transaction to a file"));
m_cmd_binder.set_handler("mms",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms [<subcommand> [<subcommand_parameters>]]"),
+ tr(USAGE_MMS),
tr("Interface with the MMS (Multisig Messaging System)\n"
"<subcommand> is one of:\n"
" init, info, signer, list, next, sync, transfer, delete, send, receive, export, note, show, set, help\n"
@@ -2795,112 +2893,112 @@ simple_wallet::simple_wallet()
"Get help about a subcommand with: help mms <subcommand>, or mms help <subcommand>"));
m_cmd_binder.set_handler("mms init",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms init <required_signers>/<authorized_signers> <own_label> <own_transport_address>"),
+ tr(USAGE_MMS_INIT),
tr("Initialize and configure the MMS for M/N = number of required signers/number of authorized signers multisig"));
m_cmd_binder.set_handler("mms info",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms info"),
+ tr(USAGE_MMS_INFO),
tr("Display current MMS configuration"));
m_cmd_binder.set_handler("mms signer",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms signer [<number> <label> [<transport_address> [<monero_address>]]]"),
+ tr(USAGE_MMS_SIGNER),
tr("Set or modify authorized signer info (single-word label, transport address, Monero address), or list all signers"));
m_cmd_binder.set_handler("mms list",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms list"),
+ tr(USAGE_MMS_LIST),
tr("List all messages"));
m_cmd_binder.set_handler("mms next",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms next [sync]"),
+ tr(USAGE_MMS_NEXT),
tr("Evaluate the next possible multisig-related action(s) according to wallet state, and execute or offer for choice\n"
"By using 'sync' processing of waiting messages with multisig sync info can be forced regardless of wallet state"));
m_cmd_binder.set_handler("mms sync",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms sync"),
+ tr(USAGE_MMS_SYNC),
tr("Force generation of multisig sync info regardless of wallet state, to recover from special situations like \"stale data\" errors"));
m_cmd_binder.set_handler("mms transfer",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms transfer <transfer_command_arguments>"),
+ tr(USAGE_MMS_TRANSFER),
tr("Initiate transfer with MMS support; arguments identical to normal 'transfer' command arguments, for info see there"));
m_cmd_binder.set_handler("mms delete",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms delete (<message_id> | all)"),
+ tr(USAGE_MMS_DELETE),
tr("Delete a single message by giving its id, or delete all messages by using 'all'"));
m_cmd_binder.set_handler("mms send",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms send [<message_id>]"),
+ tr(USAGE_MMS_SEND),
tr("Send a single message by giving its id, or send all waiting messages"));
m_cmd_binder.set_handler("mms receive",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms receive"),
+ tr(USAGE_MMS_RECEIVE),
tr("Check right away for new messages to receive"));
m_cmd_binder.set_handler("mms export",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms export <message_id"),
+ tr(USAGE_MMS_EXPORT),
tr("Write the content of a message to a file \"mms_message_content\""));
m_cmd_binder.set_handler("mms note",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms note [<label> <text>]"),
+ tr(USAGE_MMS_NOTE),
tr("Send a one-line message to an authorized signer, identified by its label, or show any waiting unread notes"));
m_cmd_binder.set_handler("mms show",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms show <message_id>"),
+ tr(USAGE_MMS_SHOW),
tr("Show detailed info about a single message"));
m_cmd_binder.set_handler("mms set",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms set <option_name> [<option_value>]"),
+ tr(USAGE_MMS_SET),
tr("Available options:\n "
"auto-send <1|0>\n "
" Whether to automatically send newly generated messages right away.\n "));
m_cmd_binder.set_handler("mms send_message_config",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms send_signer_config"),
+ tr(USAGE_MMS_SEND_SIGNER_CONFIG),
tr("Send completed signer config to all other authorized signers"));
m_cmd_binder.set_handler("mms start_auto_config",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms start_auto_config [<label> <label> ...]"),
+ tr(USAGE_MMS_START_AUTO_CONFIG),
tr("Start auto-config at the auto-config manager's wallet by issuing auto-config tokens and optionally set others' labels"));
m_cmd_binder.set_handler("mms stop_auto_config",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms stop_auto_config"),
+ tr(USAGE_MMS_STOP_AUTO_CONFIG),
tr("Delete any auto-config tokens and abort a auto-config process"));
m_cmd_binder.set_handler("mms auto_config",
boost::bind(&simple_wallet::mms, this, _1),
- tr("mms auto_config <auto_config_token>"),
+ tr(USAGE_MMS_AUTO_CONFIG),
tr("Start auto-config by using the token received from the auto-config manager"));
m_cmd_binder.set_handler("print_ring",
boost::bind(&simple_wallet::print_ring, this, _1),
- tr("print_ring <key_image> | <txid>"),
+ tr(USAGE_PRINT_RING),
tr("Print the ring(s) used to spend a given key image or transaction (if the ring size is > 1)\n\n"
"Output format:\n"
"Key Image, \"absolute\", list of rings"));
m_cmd_binder.set_handler("set_ring",
boost::bind(&simple_wallet::set_ring, this, _1),
- tr("set_ring <filename> | ( <key_image> absolute|relative <index> [<index>...] )"),
+ tr(USAGE_SET_RING),
tr("Set the ring used for a given key image, so it can be reused in a fork"));
m_cmd_binder.set_handler("save_known_rings",
boost::bind(&simple_wallet::save_known_rings, this, _1),
- tr("save_known_rings"),
+ tr(USAGE_SAVE_KNOWN_RINGS),
tr("Save known rings to the shared rings database"));
m_cmd_binder.set_handler("mark_output_spent",
boost::bind(&simple_wallet::blackball, this, _1),
- tr("mark_output_spent <amount>/<offset> | <filename> [add]"),
+ tr(USAGE_MARK_OUTPUT_SPENT),
tr("Mark output(s) as spent so they never get selected as fake outputs in a ring"));
m_cmd_binder.set_handler("mark_output_unspent",
boost::bind(&simple_wallet::unblackball, this, _1),
- tr("mark_output_unspent <amount>/<offset>"),
+ tr(USAGE_MARK_OUTPUT_UNSPENT),
tr("Marks an output as unspent so it may get selected as a fake output in a ring"));
m_cmd_binder.set_handler("is_output_spent",
boost::bind(&simple_wallet::blackballed, this, _1),
- tr("is_output_spent <amount>/<offset>"),
+ tr(USAGE_IS_OUTPUT_SPENT),
tr("Checks whether an output is marked as spent"));
m_cmd_binder.set_handler("version",
boost::bind(&simple_wallet::version, this, _1),
- tr("version"),
+ tr(USAGE_VERSION),
tr("Returns version information"));
m_cmd_binder.set_handler("help",
boost::bind(&simple_wallet::help, this, _1),
- tr("help [<command>]"),
+ tr(USAGE_HELP),
tr("Show the help section or the documentation about a <command>."));
}
//----------------------------------------------------------------------------------------------------
@@ -2947,6 +3045,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
success_msg_writer() << "subaddress-lookahead = " << lookahead.first << ":" << lookahead.second;
success_msg_writer() << "segregation-height = " << m_wallet->segregation_height();
success_msg_writer() << "ignore-fractional-outputs = " << m_wallet->ignore_fractional_outputs();
+ success_msg_writer() << "track-uses = " << m_wallet->track_uses();
success_msg_writer() << "device_name = " << m_wallet->device_name();
return true;
}
@@ -3003,6 +3102,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
CHECK_SIMPLE_VARIABLE("subaddress-lookahead", set_subaddress_lookahead, tr("<major>:<minor>"));
CHECK_SIMPLE_VARIABLE("segregation-height", set_segregation_height, tr("unsigned integer"));
CHECK_SIMPLE_VARIABLE("ignore-fractional-outputs", set_ignore_fractional_outputs, tr("0 or 1"));
+ CHECK_SIMPLE_VARIABLE("track-uses", set_track_uses, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("device-name", set_device_name, tr("<device_name[:device_spec]>"));
}
fail_msg_writer() << tr("set: unrecognized argument(s)");
@@ -3014,7 +3114,7 @@ bool simple_wallet::set_log(const std::vector<std::string> &args)
{
if(args.size() > 1)
{
- fail_msg_writer() << tr("usage: set_log <log_level_number_0-4> | <categories>");
+ PRINT_USAGE(USAGE_SET_LOG);
return true;
}
if(!args.empty())
@@ -3024,7 +3124,7 @@ bool simple_wallet::set_log(const std::vector<std::string> &args)
{
if(4 < level)
{
- fail_msg_writer() << tr("wrong number range, use: set_log <log_level_number_0-4> | <categories>");
+ fail_msg_writer() << boost::format(tr("wrong number range, use: %s")) % USAGE_SET_LOG;
return true;
}
mlog_set_log_level(level);
@@ -4320,7 +4420,7 @@ bool simple_wallet::start_mining(const std::vector<std::string>& args)
if (!ok)
{
- fail_msg_writer() << tr("invalid arguments. Please use start_mining [<number_of_threads>] [do_bg_mining] [ignore_battery]");
+ PRINT_USAGE(USAGE_START_MINING);
return true;
}
@@ -4362,7 +4462,7 @@ bool simple_wallet::set_daemon(const std::vector<std::string>& args)
if (args.size() < 1)
{
- fail_msg_writer() << tr("missing daemon URL argument");
+ PRINT_USAGE(USAGE_SET_DAEMON);
return true;
}
@@ -4707,7 +4807,7 @@ bool simple_wallet::show_balance(const std::vector<std::string>& args/* = std::v
{
if (args.size() > 1 || (args.size() == 1 && args[0] != "detail"))
{
- fail_msg_writer() << tr("usage: balance [detail]");
+ PRINT_USAGE(USAGE_SHOW_BALANCE);
return true;
}
LOCK_IDLE_SCOPE();
@@ -4719,7 +4819,7 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
{
if (args.size() > 3)
{
- fail_msg_writer() << tr("usage: incoming_transfers [available|unavailable] [verbose] [index=<N1>[,<N2>[,...]]]");
+ PRINT_USAGE(USAGE_INCOMING_TRANSFERS);
return true;
}
auto local_args = args;
@@ -4728,6 +4828,7 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
bool filter = false;
bool available = false;
bool verbose = false;
+ bool uses = false;
if (local_args.size() > 0)
{
if (local_args[0] == "available")
@@ -4743,12 +4844,22 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
local_args.erase(local_args.begin());
}
}
- if (local_args.size() > 0 && local_args[0] == "verbose")
+ while (local_args.size() > 0)
{
- verbose = true;
+ if (local_args[0] == "verbose")
+ verbose = true;
+ else if (local_args[0] == "uses")
+ uses = true;
+ else
+ {
+ fail_msg_writer() << tr("Invalid keyword: ") << local_args.front();
+ break;
+ }
local_args.erase(local_args.begin());
}
+ const uint64_t blockchain_height = m_wallet->get_blockchain_current_height();
+
PAUSE_READLINE();
std::set<uint32_t> subaddr_indices;
@@ -4761,7 +4872,7 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
if (local_args.size() > 0)
{
- fail_msg_writer() << tr("usage: incoming_transfers [available|unavailable] [verbose] [index=<N1>[,<N2>[,...]]]");
+ PRINT_USAGE(USAGE_INCOMING_TRANSFERS);
return true;
}
@@ -4782,9 +4893,16 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
verbose_string = (boost::format("%68s%68s") % tr("pubkey") % tr("key image")).str();
message_writer() << boost::format("%21s%8s%12s%8s%16s%68s%16s%s") % tr("amount") % tr("spent") % tr("unlocked") % tr("ringct") % tr("global index") % tr("tx id") % tr("addr index") % verbose_string;
}
- std::string verbose_string;
+ std::string extra_string;
if (verbose)
- verbose_string = (boost::format("%68s%68s") % td.get_public_key() % (td.m_key_image_known ? epee::string_tools::pod_to_hex(td.m_key_image) : td.m_key_image_partial ? (epee::string_tools::pod_to_hex(td.m_key_image) + "/p") : std::string(64, '?'))).str();
+ extra_string += (boost::format("%68s%68s") % td.get_public_key() % (td.m_key_image_known ? epee::string_tools::pod_to_hex(td.m_key_image) : td.m_key_image_partial ? (epee::string_tools::pod_to_hex(td.m_key_image) + "/p") : std::string(64, '?'))).str();
+ if (uses)
+ {
+ std::vector<uint64_t> heights;
+ for (const auto &e: td.m_uses) heights.push_back(e.first);
+ const std::pair<std::string, std::string> line = show_outputs_line(heights, blockchain_height, td.m_spent_height);
+ extra_string += tr("Heights: ") + line.first + "\n" + line.second;
+ }
message_writer(td.m_spent ? console_color_magenta : console_color_green, false) <<
boost::format("%21s%8s%12s%8s%16u%68s%16u%s") %
print_money(td.amount()) %
@@ -4794,7 +4912,7 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
td.m_global_output_index %
td.m_txid %
td.m_subaddr_index.minor %
- verbose_string;
+ extra_string;
++transfers_found;
}
}
@@ -4826,7 +4944,7 @@ bool simple_wallet::show_payments(const std::vector<std::string> &args)
{
if(args.empty())
{
- fail_msg_writer() << tr("expected at least one payment ID");
+ PRINT_USAGE(USAGE_PAYMENTS);
return true;
}
@@ -4946,6 +5064,33 @@ bool simple_wallet::rescan_spent(const std::vector<std::string> &args)
return true;
}
//----------------------------------------------------------------------------------------------------
+std::pair<std::string, std::string> simple_wallet::show_outputs_line(const std::vector<uint64_t> &heights, uint64_t blockchain_height, uint64_t highlight_height) const
+{
+ std::stringstream ostr;
+
+ for (uint64_t h: heights)
+ blockchain_height = std::max(blockchain_height, h);
+
+ for (size_t j = 0; j < heights.size(); ++j)
+ ostr << (heights[j] == highlight_height ? " *" : " ") << heights[j];
+
+ // visualize the distribution, using the code by moneroexamples onion-monero-viewer
+ const uint64_t resolution = 79;
+ std::string ring_str(resolution, '_');
+ for (size_t j = 0; j < heights.size(); ++j)
+ {
+ uint64_t pos = (heights[j] * resolution) / blockchain_height;
+ ring_str[pos] = 'o';
+ }
+ if (highlight_height < blockchain_height)
+ {
+ uint64_t pos = (highlight_height * resolution) / blockchain_height;
+ ring_str[pos] = '*';
+ }
+
+ return std::make_pair(ostr.str(), ring_str);
+}
+//----------------------------------------------------------------------------------------------------
bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending_tx>& ptx_vector, std::ostream& ostr)
{
uint32_t version;
@@ -5016,21 +5161,18 @@ bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending
}
}
ostr << tr("\nOriginating block heights: ");
- for (size_t j = 0; j < absolute_offsets.size(); ++j)
- ostr << tr(j == source.real_output ? " *" : " ") << res.outs[j].height;
spent_key_height[i] = res.outs[source.real_output].height;
spent_key_txid [i] = res.outs[source.real_output].txid;
- // visualize the distribution, using the code by moneroexamples onion-monero-viewer
- const uint64_t resolution = 79;
- std::string ring_str(resolution, '_');
+ std::vector<uint64_t> heights(absolute_offsets.size(), 0);
+ uint64_t highlight_height = std::numeric_limits<uint64_t>::max();
for (size_t j = 0; j < absolute_offsets.size(); ++j)
{
- uint64_t pos = (res.outs[j].height * resolution) / blockchain_height;
- ring_str[pos] = 'o';
+ heights[j] = res.outs[j].height;
+ if (j == source.real_output)
+ highlight_height = heights[j];
}
- uint64_t pos = (res.outs[source.real_output].height * resolution) / blockchain_height;
- ring_str[pos] = '*';
- ostr << tr("\n|") << ring_str << tr("|\n");
+ std::pair<std::string, std::string> ring_str = show_outputs_line(heights, highlight_height);
+ ostr << ring_str.first << tr("\n|") << ring_str.second << tr("|\n");
}
// warn if rings contain keys originating from the same tx or temporally very close block heights
bool are_keys_from_same_tx = false;
@@ -5659,7 +5801,14 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
{
auto print_usage = [below]()
{
- fail_msg_writer() << boost::format(tr("usage: %s [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id>]")) % (below ? "sweep_below" : "sweep_all");
+ if (below)
+ {
+ PRINT_USAGE(USAGE_SWEEP_BELOW);
+ }
+ else
+ {
+ PRINT_USAGE(USAGE_SWEEP_ALL);
+ }
};
if (args_.size() == 0)
{
@@ -6077,7 +6226,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
if (local_args.size() != 2)
{
- fail_msg_writer() << tr("usage: sweep_single [<priority>] [<ring_size>] [outputs=<N>] <key_image> <address> [<payment_id>]");
+ PRINT_USAGE(USAGE_SWEEP_SINGLE);
return true;
}
@@ -6241,7 +6390,7 @@ bool simple_wallet::donate(const std::vector<std::string> &args_)
std::vector<std::string> local_args = args_;
if(local_args.empty() || local_args.size() > 5)
{
- fail_msg_writer() << tr("usage: donate [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <amount> [<payment_id>]");
+ PRINT_USAGE(USAGE_DONATE);
return true;
}
std::string amount_str;
@@ -6256,8 +6405,18 @@ bool simple_wallet::donate(const std::vector<std::string> &args_)
local_args.pop_back();
}
// get amount and pop
- amount_str = local_args.back();
- local_args.pop_back();
+ uint64_t amount;
+ bool ok = cryptonote::parse_amount(amount, local_args.back());
+ if (ok && amount != 0)
+ {
+ amount_str = local_args.back();
+ local_args.pop_back();
+ }
+ else
+ {
+ fail_msg_writer() << tr("amount is wrong: ") << local_args.back() << ", " << tr("expected number from 0 to ") << print_money(std::numeric_limits<uint64_t>::max());
+ return true;
+ }
// push back address, amount, payment id
std::string address_str;
if (m_wallet->nettype() != cryptonote::MAINNET)
@@ -6454,7 +6613,7 @@ bool simple_wallet::sign_transfer(const std::vector<std::string> &args_)
}
if (args_.size() > 1 || (args_.size() == 1 && args_[0] != "export_raw"))
{
- fail_msg_writer() << tr("usage: sign_transfer [export_raw]");
+ PRINT_USAGE(USAGE_SIGN_TRANSFER);
return true;
}
@@ -6544,7 +6703,7 @@ bool simple_wallet::get_tx_key(const std::vector<std::string> &args_)
return true;
}
if(local_args.size() != 1) {
- fail_msg_writer() << tr("usage: get_tx_key <txid>");
+ PRINT_USAGE(USAGE_GET_TX_KEY);
return true;
}
@@ -6580,7 +6739,7 @@ bool simple_wallet::set_tx_key(const std::vector<std::string> &args_)
std::vector<std::string> local_args = args_;
if(local_args.size() != 2) {
- fail_msg_writer() << tr("usage: set_tx_key <txid> <tx_key>");
+ PRINT_USAGE(USAGE_SET_TX_KEY);
return true;
}
@@ -6642,7 +6801,7 @@ bool simple_wallet::get_tx_proof(const std::vector<std::string> &args)
}
if (args.size() != 2 && args.size() != 3)
{
- fail_msg_writer() << tr("usage: get_tx_proof <txid> <address> [<message>]");
+ PRINT_USAGE(USAGE_GET_TX_PROOF);
return true;
}
@@ -6683,7 +6842,7 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_)
std::vector<std::string> local_args = args_;
if(local_args.size() != 3) {
- fail_msg_writer() << tr("usage: check_tx_key <txid> <txkey> <address>");
+ PRINT_USAGE(USAGE_CHECK_TX_KEY);
return true;
}
@@ -6769,7 +6928,7 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_)
bool simple_wallet::check_tx_proof(const std::vector<std::string> &args)
{
if(args.size() != 3 && args.size() != 4) {
- fail_msg_writer() << tr("usage: check_tx_proof <txid> <address> <signature_file> [<message>]");
+ PRINT_USAGE(USAGE_CHECK_TX_PROOF);
return true;
}
@@ -6852,7 +7011,7 @@ bool simple_wallet::get_spend_proof(const std::vector<std::string> &args)
return true;
}
if(args.size() != 1 && args.size() != 2) {
- fail_msg_writer() << tr("usage: get_spend_proof <txid> [<message>]");
+ PRINT_USAGE(USAGE_GET_SPEND_PROOF);
return true;
}
@@ -6893,7 +7052,7 @@ bool simple_wallet::get_spend_proof(const std::vector<std::string> &args)
bool simple_wallet::check_spend_proof(const std::vector<std::string> &args)
{
if(args.size() != 2 && args.size() != 3) {
- fail_msg_writer() << tr("usage: check_spend_proof <txid> <signature_file> [<message>]");
+ PRINT_USAGE(USAGE_CHECK_SPEND_PROOF);
return true;
}
@@ -6936,7 +7095,7 @@ bool simple_wallet::get_reserve_proof(const std::vector<std::string> &args)
return true;
}
if(args.size() != 1 && args.size() != 2) {
- fail_msg_writer() << tr("usage: get_reserve_proof (all|<amount>) [<message>]");
+ PRINT_USAGE(USAGE_GET_RESERVE_PROOF);
return true;
}
@@ -6982,7 +7141,7 @@ bool simple_wallet::get_reserve_proof(const std::vector<std::string> &args)
bool simple_wallet::check_reserve_proof(const std::vector<std::string> &args)
{
if(args.size() != 2 && args.size() != 3) {
- fail_msg_writer() << tr("usage: check_reserve_proof <address> <signature_file> [<message>]");
+ PRINT_USAGE(USAGE_CHECK_RESERVE_PROOF);
return true;
}
@@ -7419,7 +7578,7 @@ bool simple_wallet::unspent_outputs(const std::vector<std::string> &args_)
{
if(args_.size() > 3)
{
- fail_msg_writer() << tr("usage: unspent_outputs [index=<N1>[,<N2>,...]] [<min_amount> [<max_amount>]]");
+ PRINT_USAGE(USAGE_UNSPENT_OUTPUTS);
return true;
}
auto local_args = args_;
@@ -7560,7 +7719,7 @@ bool simple_wallet::rescan_blockchain(const std::vector<std::string> &args_)
{
if (args_[0] != "hard")
{
- fail_msg_writer() << tr("usage: rescan_bc [hard]");
+ PRINT_USAGE(USAGE_RESCAN_BC);
return true;
}
hard = true;
@@ -7805,14 +7964,7 @@ bool simple_wallet::account(const std::vector<std::string> &args/* = std::vector
}
else
{
- fail_msg_writer() << tr("usage:\n"
- " account\n"
- " account new <label text with white spaces allowed>\n"
- " account switch <index>\n"
- " account label <index> <label text with white spaces allowed>\n"
- " account tag <tag_name> <account_index_1> [<account_index_2> ...]\n"
- " account untag <account_index_1> [<account_index_2> ...]\n"
- " account tag_description <tag_name> <description>");
+ PRINT_USAGE(USAGE_ACCOUNT);
}
return true;
}
@@ -7967,7 +8119,7 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
}
else
{
- fail_msg_writer() << tr("usage: address [ new <label text with white spaces allowed> | all | <index_min> [<index_max>] | label <index> <label text with white spaces allowed> ]");
+ PRINT_USAGE(USAGE_ADDRESS);
}
return true;
@@ -7978,7 +8130,7 @@ bool simple_wallet::print_integrated_address(const std::vector<std::string> &arg
crypto::hash8 payment_id;
if (args.size() > 1)
{
- fail_msg_writer() << tr("usage: integrated_address [payment ID]");
+ PRINT_USAGE(USAGE_INTEGRATED_ADDRESS);
return true;
}
if (args.size() == 0)
@@ -8030,7 +8182,7 @@ bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::v
}
else if (args.size() == 1 || (args[0] != "add" && args[0] != "delete"))
{
- fail_msg_writer() << tr("usage: address_book [(add (<address> [pid <long or short payment id>])|<integrated address> [<description possibly with whitespaces>])|(delete <index>)]");
+ PRINT_USAGE(USAGE_ADDRESS_BOOK);
return true;
}
else if (args[0] == "add")
@@ -8105,7 +8257,7 @@ bool simple_wallet::set_tx_note(const std::vector<std::string> &args)
{
if (args.size() == 0)
{
- fail_msg_writer() << tr("usage: set_tx_note [txid] free text note");
+ PRINT_USAGE(USAGE_SET_TX_NOTE);
return true;
}
@@ -8133,7 +8285,7 @@ bool simple_wallet::get_tx_note(const std::vector<std::string> &args)
{
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: get_tx_note [txid]");
+ PRINT_USAGE(USAGE_GET_TX_NOTE);
return true;
}
@@ -8174,7 +8326,7 @@ bool simple_wallet::get_description(const std::vector<std::string> &args)
{
if (args.size() != 0)
{
- fail_msg_writer() << tr("usage: get_description");
+ PRINT_USAGE(USAGE_GET_DESCRIPTION);
return true;
}
@@ -8247,7 +8399,7 @@ bool simple_wallet::sign(const std::vector<std::string> &args)
}
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: sign <filename>");
+ PRINT_USAGE(USAGE_SIGN);
return true;
}
if (m_wallet->watch_only())
@@ -8281,7 +8433,7 @@ bool simple_wallet::verify(const std::vector<std::string> &args)
{
if (args.size() != 3)
{
- fail_msg_writer() << tr("usage: verify <filename> <address> <signature>");
+ PRINT_USAGE(USAGE_VERIFY);
return true;
}
std::string filename = args[0];
@@ -8324,7 +8476,7 @@ bool simple_wallet::export_key_images(const std::vector<std::string> &args)
}
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: export_key_images <filename>");
+ PRINT_USAGE(USAGE_EXPORT_KEY_IMAGES);
return true;
}
if (m_wallet->watch_only())
@@ -8373,7 +8525,7 @@ bool simple_wallet::import_key_images(const std::vector<std::string> &args)
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: import_key_images <filename>");
+ PRINT_USAGE(USAGE_IMPORT_KEY_IMAGES);
return true;
}
std::string filename = args[0];
@@ -8480,7 +8632,7 @@ bool simple_wallet::export_outputs(const std::vector<std::string> &args)
}
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: export_outputs <filename>");
+ PRINT_USAGE(USAGE_EXPORT_OUTPUTS);
return true;
}
@@ -8520,7 +8672,7 @@ bool simple_wallet::import_outputs(const std::vector<std::string> &args)
}
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: import_outputs <filename>");
+ PRINT_USAGE(USAGE_IMPORT_OUTPUTS);
return true;
}
std::string filename = args[0];
@@ -8552,7 +8704,7 @@ bool simple_wallet::show_transfer(const std::vector<std::string> &args)
{
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: show_transfer <txid>");
+ PRINT_USAGE(USAGE_SHOW_TRANSFER);
return true;
}
@@ -8784,7 +8936,7 @@ int main(int argc, char* argv[])
bool should_terminate = false;
std::tie(vm, should_terminate) = wallet_args::main(
argc, argv,
- "monero-wallet-cli [--wallet-file=<file>|--generate-new-wallet=<file>] [<COMMAND>]",
+ "monero-wallet-cli [--wallet-file=<filename>|--generate-new-wallet=<filename>] [<COMMAND>]",
sw::tr("This is the command line monero wallet. It needs to connect to a monero\ndaemon to work correctly.\nWARNING: Do not reuse your Monero keys on another fork, UNLESS this fork has key reuse mitigations built in. Doing so will harm your privacy."),
desc_params,
positional_options,
@@ -9843,6 +9995,7 @@ bool simple_wallet::mms(const std::vector<std::string> &args)
catch (const std::exception &e)
{
fail_msg_writer() << tr("Error in MMS command: ") << e.what();
+ PRINT_USAGE(USAGE_MMS);
return true;
}
return true;
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index 5010e3adc..e49da8c18 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -142,6 +142,7 @@ namespace cryptonote
bool set_subaddress_lookahead(const std::vector<std::string> &args = std::vector<std::string>());
bool set_segregation_height(const std::vector<std::string> &args = std::vector<std::string>());
bool set_ignore_fractional_outputs(const std::vector<std::string> &args = std::vector<std::string>());
+ bool set_track_uses(const std::vector<std::string> &args = std::vector<std::string>());
bool set_device_name(const std::vector<std::string> &args = std::vector<std::string>());
bool help(const std::vector<std::string> &args = std::vector<std::string>());
bool start_mining(const std::vector<std::string> &args);
@@ -251,6 +252,7 @@ namespace cryptonote
bool print_seed(bool encrypted);
void key_images_sync_intern();
void on_refresh_finished(uint64_t start_height, uint64_t fetched_blocks, bool is_init, bool received_money);
+ std::pair<std::string, std::string> show_outputs_line(const std::vector<uint64_t> &heights, uint64_t blockchain_height, uint64_t highlight_height = std::numeric_limits<uint64_t>::max()) const;
struct transfer_view
{
diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt
index 8425e4a03..2991f75c5 100644
--- a/src/wallet/CMakeLists.txt
+++ b/src/wallet/CMakeLists.txt
@@ -139,6 +139,12 @@ if (BUILD_GUI_DEPS)
endif()
install(TARGETS wallet_merged
ARCHIVE DESTINATION ${lib_folder})
+
+ install(FILES ${TREZOR_DEP_LIBS}
+ DESTINATION ${lib_folder})
+ file(WRITE "trezor_link_flags.txt" ${TREZOR_DEP_LINKER})
+ install(FILES "trezor_link_flags.txt"
+ DESTINATION ${lib_folder})
endif()
add_subdirectory(api)
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 0d2faca54..2080c1832 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -894,6 +894,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
m_key_reuse_mitigation2(true),
m_segregation_height(0),
m_ignore_fractional_outputs(true),
+ m_track_uses(false),
m_is_initialized(false),
m_kdf_rounds(kdf_rounds),
is_old_file_format(false),
@@ -1446,8 +1447,9 @@ void wallet2::cache_tx_data(const cryptonote::transaction& tx, const crypto::has
}
}
//----------------------------------------------------------------------------------------------------
-void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data)
+void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache)
{
+ PERF_TIMER(process_new_transaction);
// In this function, tx (probably) only contains the base information
// (that is, the prunable stuff may or may not be included)
if (!miner_tx && !pool)
@@ -1684,6 +1686,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
if (!m_multisig && !m_watch_only)
m_key_images[td.m_key_image] = m_transfers.size()-1;
m_pub_keys[tx_scan_info[o].in_ephemeral.pub] = m_transfers.size()-1;
+ if (output_tracker_cache)
+ (*output_tracker_cache)[std::make_pair(tx.vout[o].amount, td.m_global_output_index)] = m_transfers.size() - 1;
if (m_multisig)
{
THROW_WALLET_EXCEPTION_IF(!m_multisig_rescan_k && m_multisig_rescan_info,
@@ -1749,6 +1753,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_mask = rct::identity();
td.m_rct = false;
}
+ if (output_tracker_cache)
+ (*output_tracker_cache)[std::make_pair(tx.vout[o].amount, td.m_global_output_index)] = kit->second;
if (m_multisig)
{
THROW_WALLET_EXCEPTION_IF(!m_multisig_rescan_k && m_multisig_rescan_info,
@@ -1780,11 +1786,12 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
{
if(in.type() != typeid(cryptonote::txin_to_key))
continue;
- auto it = m_key_images.find(boost::get<cryptonote::txin_to_key>(in).k_image);
+ const cryptonote::txin_to_key &in_to_key = boost::get<cryptonote::txin_to_key>(in);
+ auto it = m_key_images.find(in_to_key.k_image);
if(it != m_key_images.end())
{
transfer_details& td = m_transfers[it->second];
- uint64_t amount = boost::get<cryptonote::txin_to_key>(in).amount;
+ uint64_t amount = in_to_key.amount;
if (amount > 0)
{
if(amount != td.amount())
@@ -1815,6 +1822,34 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
m_callback->on_money_spent(height, txid, tx, amount, tx, td.m_subaddr_index);
}
}
+
+ if (!pool && m_track_uses)
+ {
+ PERF_TIMER(track_uses);
+ const uint64_t amount = in_to_key.amount;
+ std::vector<uint64_t> offsets = cryptonote::relative_output_offsets_to_absolute(in_to_key.key_offsets);
+ if (output_tracker_cache)
+ {
+ for (uint64_t offset: offsets)
+ {
+ const std::map<std::pair<uint64_t, uint64_t>, size_t>::const_iterator i = output_tracker_cache->find(std::make_pair(amount, offset));
+ if (i != output_tracker_cache->end())
+ {
+ size_t idx = i->second;
+ THROW_WALLET_EXCEPTION_IF(idx >= m_transfers.size(), error::wallet_internal_error, "Output tracker cache index out of range");
+ m_transfers[idx].m_uses.push_back(std::make_pair(height, txid));
+ }
+ }
+ }
+ else for (transfer_details &td: m_transfers)
+ {
+ if (amount != in_to_key.amount)
+ continue;
+ for (uint64_t offset: offsets)
+ if (offset == td.m_global_output_index)
+ td.m_uses.push_back(std::make_pair(height, txid));
+ }
+ }
}
uint64_t fee = miner_tx ? 0 : tx.version == 1 ? tx_money_spent_in_ins - get_outs_money_amount(tx) : tx.rct_signatures.txnFee;
@@ -1997,7 +2032,7 @@ void wallet2::process_outgoing(const crypto::hash &txid, const cryptonote::trans
add_rings(tx);
}
//----------------------------------------------------------------------------------------------------
-void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset)
+void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache)
{
THROW_WALLET_EXCEPTION_IF(bche.txs.size() + 1 != parsed_block.o_indices.indices.size(), error::wallet_internal_error,
"block transactions=" + std::to_string(bche.txs.size()) +
@@ -2010,7 +2045,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry
{
TIME_MEASURE_START(miner_tx_handle_time);
if (m_refresh_type != RefreshNoCoinbase)
- process_new_transaction(get_transaction_hash(b.miner_tx), b.miner_tx, parsed_block.o_indices.indices[0].indices, height, b.timestamp, true, false, false, tx_cache_data[tx_cache_data_offset]);
+ process_new_transaction(get_transaction_hash(b.miner_tx), b.miner_tx, parsed_block.o_indices.indices[0].indices, height, b.timestamp, true, false, false, tx_cache_data[tx_cache_data_offset], output_tracker_cache);
++tx_cache_data_offset;
TIME_MEASURE_FINISH(miner_tx_handle_time);
@@ -2019,7 +2054,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry
THROW_WALLET_EXCEPTION_IF(bche.txs.size() != parsed_block.txes.size(), error::wallet_internal_error, "Wrong amount of transactions for block");
for (size_t idx = 0; idx < b.tx_hashes.size(); ++idx)
{
- process_new_transaction(b.tx_hashes[idx], parsed_block.txes[idx], parsed_block.o_indices.indices[idx+1].indices, height, b.timestamp, false, false, false, tx_cache_data[tx_cache_data_offset++]);
+ process_new_transaction(b.tx_hashes[idx], parsed_block.txes[idx], parsed_block.o_indices.indices[idx+1].indices, height, b.timestamp, false, false, false, tx_cache_data[tx_cache_data_offset++], output_tracker_cache);
}
TIME_MEASURE_FINISH(txs_handle_time);
m_last_block_reward = cryptonote::get_outs_money_amount(b.miner_tx);
@@ -2117,7 +2152,7 @@ void wallet2::pull_hashes(uint64_t start_height, uint64_t &blocks_start_height,
hashes = std::move(res.m_block_ids);
}
//----------------------------------------------------------------------------------------------------
-void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added)
+void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache)
{
size_t current_index = start_height;
blocks_added = 0;
@@ -2224,7 +2259,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
if(current_index >= m_blockchain.size())
{
- process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset);
+ process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset, output_tracker_cache);
++blocks_added;
}
else if(bl_id != m_blockchain[current_index])
@@ -2236,7 +2271,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
string_tools::pod_to_hex(m_blockchain[current_index]));
detach_blockchain(current_index);
- process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset);
+ process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset, output_tracker_cache);
}
else
{
@@ -2669,6 +2704,17 @@ bool wallet2::delete_address_book_row(std::size_t row_id) {
}
//----------------------------------------------------------------------------------------------------
+std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> wallet2::create_output_tracker_cache() const
+{
+ std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> cache{new std::map<std::pair<uint64_t, uint64_t>, size_t>()};
+ for (size_t i = 0; i < m_transfers.size(); ++i)
+ {
+ const transfer_details &td = m_transfers[i];
+ (*cache)[std::make_pair(td.is_rct() ? 0 : td.amount(), td.m_global_output_index)] = i;
+ }
+ return cache;
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blocks_fetched, bool& received_money)
{
if(m_light_wallet) {
@@ -2715,6 +2761,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
std::vector<cryptonote::block_complete_entry> blocks;
std::vector<parsed_block> parsed_blocks;
bool refreshed = false;
+ std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> output_tracker_cache;
// pull the first set of blocks
get_short_chain_history(short_chain_history, (m_first_refresh_done || trusted_daemon) ? 1 : FIRST_REFRESH_GRANULARITY);
@@ -2768,7 +2815,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
{
try
{
- process_parsed_blocks(blocks_start_height, blocks, parsed_blocks, added_blocks);
+ process_parsed_blocks(blocks_start_height, blocks, parsed_blocks, added_blocks, output_tracker_cache.get());
}
catch (const tools::error::out_of_hashchain_bounds_error&)
{
@@ -2811,6 +2858,11 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
throw std::runtime_error("proxy exception in refresh thread");
}
+ // if we've got at least 10 blocks to refresh, assume we're starting
+ // a long refresh, and setup a tracking output cache if we need to
+ if (m_track_uses && !output_tracker_cache && next_blocks.size() >= 10)
+ output_tracker_cache = create_output_tracker_cache();
+
// switch to the new blocks from the daemon
blocks_start_height = next_blocks_start_height;
blocks = std::move(next_blocks);
@@ -3183,6 +3235,9 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
value2.SetInt(m_ignore_fractional_outputs ? 1 : 0);
json.AddMember("ignore_fractional_outputs", value2, json.GetAllocator());
+ value2.SetInt(m_track_uses ? 1 : 0);
+ json.AddMember("track_uses", value2, json.GetAllocator());
+
value2.SetUint(m_subaddress_lookahead_major);
json.AddMember("subaddress_lookahead_major", value2, json.GetAllocator());
@@ -3329,6 +3384,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_key_reuse_mitigation2 = true;
m_segregation_height = 0;
m_ignore_fractional_outputs = true;
+ m_track_uses = false;
m_subaddress_lookahead_major = SUBADDRESS_LOOKAHEAD_MAJOR;
m_subaddress_lookahead_minor = SUBADDRESS_LOOKAHEAD_MINOR;
m_original_keys_available = false;
@@ -3481,6 +3537,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_segregation_height = field_segregation_height;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, ignore_fractional_outputs, int, Int, false, true);
m_ignore_fractional_outputs = field_ignore_fractional_outputs;
+ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, track_uses, int, Int, false, false);
+ m_track_uses = field_track_uses;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_major, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MAJOR);
m_subaddress_lookahead_major = field_subaddress_lookahead_major;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_minor, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MINOR);
@@ -5267,6 +5325,10 @@ void wallet2::rescan_blockchain(bool hard, bool refresh)
m_transfers.clear();
m_key_images.clear();
m_pub_keys.clear();
+ m_unconfirmed_txs.clear();
+ m_payments.clear();
+ m_confirmed_txs.clear();
+ m_unconfirmed_payments.clear();
m_scanned_pool_txs[0].clear();
m_scanned_pool_txs[1].clear();
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index ace01a235..5b1988080 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -273,6 +273,7 @@ namespace tools
bool m_key_image_partial;
std::vector<rct::key> m_multisig_k;
std::vector<multisig_info> m_multisig_info; // one per other participant
+ std::vector<std::pair<uint64_t, crypto::hash>> m_uses;
bool is_rct() const { return m_rct; }
uint64_t amount() const { return m_amount; }
@@ -297,6 +298,7 @@ namespace tools
FIELD(m_key_image_partial)
FIELD(m_multisig_k)
FIELD(m_multisig_info)
+ FIELD(m_uses)
END_SERIALIZE()
};
@@ -984,6 +986,8 @@ namespace tools
void ignore_fractional_outputs(bool value) { m_ignore_fractional_outputs = value; }
bool confirm_non_default_ring_size() const { return m_confirm_non_default_ring_size; }
void confirm_non_default_ring_size(bool always) { m_confirm_non_default_ring_size = always; }
+ bool track_uses() const { return m_track_uses; }
+ void track_uses(bool value) { m_track_uses = value; }
const std::string & device_name() const { return m_device_name; }
void device_name(const std::string & device_name) { m_device_name = device_name; }
const std::string & device_derivation_path() const { return m_device_derivation_path; }
@@ -1249,8 +1253,8 @@ namespace tools
* \param password Password of wallet file
*/
bool load_keys(const std::string& keys_file_name, const epee::wipeable_string& password);
- void process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data);
- void process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset);
+ void process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
+ void process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
void detach_blockchain(uint64_t height);
void get_short_chain_history(std::list<crypto::hash>& ids, uint64_t granularity = 1) const;
bool clear();
@@ -1258,7 +1262,7 @@ namespace tools
void pull_hashes(uint64_t start_height, uint64_t& blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::vector<crypto::hash> &hashes);
void fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, bool force = false);
void pull_and_parse_next_blocks(uint64_t start_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, const std::vector<cryptonote::block_complete_entry> &prev_blocks, const std::vector<parsed_block> &prev_parsed_blocks, std::vector<cryptonote::block_complete_entry> &blocks, std::vector<parsed_block> &parsed_blocks, bool &error);
- void process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added);
+ void process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
uint64_t select_transfers(uint64_t needed_money, std::vector<size_t> unused_transfers_indices, std::vector<size_t>& selected_transfers) const;
bool prepare_file_names(const std::string& file_path);
void process_unconfirmed(const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t height);
@@ -1312,6 +1316,7 @@ namespace tools
std::unordered_set<crypto::public_key> &pkeys) const;
void cache_tx_data(const cryptonote::transaction& tx, const crypto::hash &txid, tx_cache_data &tx_cache_data) const;
+ std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> create_output_tracker_cache() const;
void setup_new_blockchain();
void create_keys_file(const std::string &wallet_, bool watch_only, const epee::wipeable_string &password, bool create_address_file);
@@ -1395,6 +1400,7 @@ namespace tools
bool m_key_reuse_mitigation2;
uint64_t m_segregation_height;
bool m_ignore_fractional_outputs;
+ bool m_track_uses;
bool m_is_initialized;
NodeRPCProxy m_node_rpc_proxy;
std::unordered_set<crypto::hash> m_scanned_pool_txs[2];
@@ -1444,7 +1450,7 @@ namespace tools
};
}
BOOST_CLASS_VERSION(tools::wallet2, 27)
-BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 10)
+BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 11)
BOOST_CLASS_VERSION(tools::wallet2::multisig_info, 1)
BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0)
BOOST_CLASS_VERSION(tools::wallet2::multisig_tx_set, 1)
@@ -1593,6 +1599,9 @@ namespace boost
return;
}
a & x.m_key_image_requested;
+ if (ver < 11)
+ return;
+ a & x.m_uses;
}
template <class Archive>