aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/epee/include/console_handler.h27
-rw-r--r--contrib/epee/include/misc_os_dependent.h15
-rw-r--r--contrib/epee/include/profile_tools.h7
-rw-r--r--contrib/epee/include/storages/levin_abstract_invoke2.h4
-rw-r--r--contrib/epee/src/mlog.cpp2
-rw-r--r--external/db_drivers/liblmdb/lmdb.h8
-rw-r--r--external/db_drivers/liblmdb/mdb.c41
-rw-r--r--external/db_drivers/liblmdb/mdb_copy.16
-rw-r--r--external/db_drivers/liblmdb/mdb_copy.c4
-rw-r--r--external/db_drivers/liblmdb/mdb_dump.16
-rw-r--r--external/db_drivers/liblmdb/mdb_dump.c6
-rw-r--r--external/db_drivers/liblmdb/mdb_stat.16
-rw-r--r--external/db_drivers/liblmdb/mdb_stat.c6
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/blockchain_utilities/CMakeLists.txt23
-rw-r--r--src/common/perf_timer.h15
-rw-r--r--src/common/scoped_message_writer.h13
-rw-r--r--src/cryptonote_basic/cryptonote_basic_impl.h2
-rw-r--r--src/cryptonote_basic/difficulty.h4
-rw-r--r--src/cryptonote_basic/miner.cpp4
-rw-r--r--src/cryptonote_config.h2
-rw-r--r--src/cryptonote_core/blockchain.cpp34
-rw-r--r--src/cryptonote_core/blockchain.h4
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp10
-rw-r--r--src/cryptonote_core/cryptonote_core.h14
-rw-r--r--src/cryptonote_protocol/block_queue.cpp2
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.h2
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl171
-rw-r--r--src/debug_utilities/CMakeLists.txt73
-rw-r--r--src/debug_utilities/cn_deserialize.cpp (renamed from src/blockchain_utilities/cn_deserialize.cpp)3
-rw-r--r--src/debug_utilities/object_sizes.cpp116
-rw-r--r--src/mnemonics/CMakeLists.txt3
-rw-r--r--src/mnemonics/electrum-words.cpp9
-rw-r--r--src/mnemonics/esperanto.h1695
-rw-r--r--src/p2p/connection_basic.cpp7
-rw-r--r--src/p2p/net_node.h1
-rw-r--r--src/p2p/net_node.inl77
-rw-r--r--src/simplewallet/simplewallet.cpp166
-rw-r--r--src/simplewallet/simplewallet.h1
-rw-r--r--src/wallet/api/wallet.cpp6
-rw-r--r--src/wallet/api/wallet.h1
-rw-r--r--src/wallet/api/wallet_manager.cpp4
-rw-r--r--src/wallet/api/wallet_manager.h1
-rw-r--r--src/wallet/node_rpc_proxy.cpp37
-rw-r--r--src/wallet/node_rpc_proxy.h25
-rw-r--r--src/wallet/wallet2.cpp66
-rw-r--r--src/wallet/wallet2.h18
-rw-r--r--src/wallet/wallet2_api.h14
-rw-r--r--src/wallet/wallet_rpc_server.cpp39
-rw-r--r--src/wallet/wallet_rpc_server.h1
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h2
-rw-r--r--tests/core_proxy/core_proxy.h2
-rw-r--r--tests/unit_tests/ban.cpp2
-rw-r--r--tests/unit_tests/mnemonics.cpp4
54 files changed, 2485 insertions, 330 deletions
diff --git a/contrib/epee/include/console_handler.h b/contrib/epee/include/console_handler.h
index e780ad4de..a3b2d30eb 100644
--- a/contrib/epee/include/console_handler.h
+++ b/contrib/epee/include/console_handler.h
@@ -293,13 +293,13 @@ namespace epee
}
template<class t_server, class chain_handler>
- bool run(t_server* psrv, chain_handler ch_handler, const std::string& prompt = "#", const std::string& usage = "")
+ bool run(t_server* psrv, chain_handler ch_handler, std::function<std::string(void)> prompt, const std::string& usage = "")
{
return run(prompt, usage, [&](const std::string& cmd) { return ch_handler(psrv, cmd); }, [&] { psrv->send_stop_signal(); });
}
template<class chain_handler>
- bool run(chain_handler ch_handler, const std::string& prompt = "#", const std::string& usage = "", std::function<void(void)> exit_handler = NULL)
+ bool run(chain_handler ch_handler, std::function<std::string(void)> prompt, const std::string& usage = "", std::function<void(void)> exit_handler = NULL)
{
return run(prompt, usage, [&](const std::string& cmd) { return ch_handler(cmd); }, exit_handler);
}
@@ -312,18 +312,19 @@ namespace epee
void print_prompt()
{
- if (!m_prompt.empty())
+ std::string prompt = m_prompt();
+ if (!prompt.empty())
{
#ifdef HAVE_READLINE
- std::string color_prompt = "\001\033[1;33m\002" + m_prompt;
- if (' ' != m_prompt.back())
+ std::string color_prompt = "\001\033[1;33m\002" + prompt;
+ if (' ' != prompt.back())
color_prompt += " ";
color_prompt += "\001\033[0m\002";
m_stdin_reader.get_readline_buffer().set_prompt(color_prompt);
#else
epee::set_console_color(epee::console_color_yellow, true);
- std::cout << m_prompt;
- if (' ' != m_prompt.back())
+ std::cout << prompt;
+ if (' ' != prompt.back())
std::cout << ' ';
epee::reset_console_color();
std::cout.flush();
@@ -333,7 +334,7 @@ namespace epee
private:
template<typename t_cmd_handler>
- bool run(const std::string& prompt, const std::string& usage, const t_cmd_handler& cmd_handler, std::function<void(void)> exit_handler)
+ bool run(std::function<std::string(void)> prompt, const std::string& usage, const t_cmd_handler& cmd_handler, std::function<void(void)> exit_handler)
{
bool continue_handle = true;
m_prompt = prompt;
@@ -394,7 +395,7 @@ namespace epee
private:
async_stdin_reader m_stdin_reader;
std::atomic<bool> m_running = {true};
- std::string m_prompt;
+ std::function<std::string(void)> m_prompt;
};
@@ -516,19 +517,23 @@ namespace epee
std::unique_ptr<boost::thread> m_console_thread;
async_console_handler m_console_handler;
public:
- bool start_handling(const std::string& prompt, const std::string& usage_string = "", std::function<void(void)> exit_handler = NULL)
+ bool start_handling(std::function<std::string(void)> prompt, const std::string& usage_string = "", std::function<void(void)> exit_handler = NULL)
{
m_console_thread.reset(new boost::thread(boost::bind(&console_handlers_binder::run_handling, this, prompt, usage_string, exit_handler)));
m_console_thread->detach();
return true;
}
+ bool start_handling(const std::string &prompt, const std::string& usage_string = "", std::function<void(void)> exit_handler = NULL)
+ {
+ return start_handling([prompt](){ return prompt; }, usage_string, exit_handler);
+ }
void stop_handling()
{
m_console_handler.stop();
}
- bool run_handling(const std::string& prompt, const std::string& usage_string, std::function<void(void)> exit_handler = NULL)
+ bool run_handling(std::function<std::string(void)> prompt, const std::string& usage_string, std::function<void(void)> exit_handler = NULL)
{
return m_console_handler.run(boost::bind(&console_handlers_binder::process_command_str, this, _1), prompt, usage_string, exit_handler);
}
diff --git a/contrib/epee/include/misc_os_dependent.h b/contrib/epee/include/misc_os_dependent.h
index 806d3e83e..69ded09e5 100644
--- a/contrib/epee/include/misc_os_dependent.h
+++ b/contrib/epee/include/misc_os_dependent.h
@@ -48,17 +48,17 @@ namespace epee
namespace misc_utils
{
- inline uint64_t get_tick_count()
+ inline uint64_t get_ns_count()
{
#if defined(_MSC_VER)
- return ::GetTickCount64();
+ return ::GetTickCount64() * 1000000;
#elif defined(WIN32)
static LARGE_INTEGER pcfreq = {0};
LARGE_INTEGER ticks;
if (!pcfreq.QuadPart)
QueryPerformanceFrequency(&pcfreq);
QueryPerformanceCounter(&ticks);
- ticks.QuadPart *= 1000; /* we want msec */
+ ticks.QuadPart *= 1000000000; /* we want nsec */
return ticks.QuadPart / pcfreq.QuadPart;
#elif defined(__MACH__)
clock_serv_t cclock;
@@ -68,16 +68,21 @@ namespace misc_utils
clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock);
- return (mts.tv_sec * 1000) + (mts.tv_nsec/1000000);
+ return (mts.tv_sec * 1000000000) + (mts.tv_nsec);
#else
struct timespec ts;
if(clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
return 0;
}
- return (ts.tv_sec * 1000) + (ts.tv_nsec/1000000);
+ return (ts.tv_sec * 1000000000) + (ts.tv_nsec);
#endif
}
+ inline uint64_t get_tick_count()
+ {
+ return get_ns_count() / 1000000;
+ }
+
inline int call_sys_cmd(const std::string& cmd)
{
diff --git a/contrib/epee/include/profile_tools.h b/contrib/epee/include/profile_tools.h
index d3b1e4db4..f285fe48b 100644
--- a/contrib/epee/include/profile_tools.h
+++ b/contrib/epee/include/profile_tools.h
@@ -57,8 +57,15 @@ namespace epee
#define TIME_MEASURE_START(var_name) uint64_t var_name = epee::misc_utils::get_tick_count();
+#define TIME_MEASURE_PAUSE(var_name) var_name = epee::misc_utils::get_tick_count() - var_name;
+#define TIME_MEASURE_RESTART(var_name) var_name = epee::misc_utils::get_tick_count() - var_name;
#define TIME_MEASURE_FINISH(var_name) var_name = epee::misc_utils::get_tick_count() - var_name;
+#define TIME_MEASURE_NS_START(var_name) uint64_t var_name = epee::misc_utils::get_ns_count();
+#define TIME_MEASURE_NS_PAUSE(var_name) var_name = epee::misc_utils::get_ns_count() - var_name;
+#define TIME_MEASURE_NS_RESTART(var_name) var_name = epee::misc_utils::get_ns_count() - var_name;
+#define TIME_MEASURE_NS_FINISH(var_name) var_name = epee::misc_utils::get_ns_count() - var_name;
+
namespace profile_tools
{
struct local_call_account
diff --git a/contrib/epee/include/storages/levin_abstract_invoke2.h b/contrib/epee/include/storages/levin_abstract_invoke2.h
index 14e7d402a..8ced9d689 100644
--- a/contrib/epee/include/storages/levin_abstract_invoke2.h
+++ b/contrib/epee/include/storages/levin_abstract_invoke2.h
@@ -115,7 +115,7 @@ namespace epee
{
typename serialization::portable_storage stg;
const_cast<t_arg&>(out_struct).store(stg);//TODO: add true const support to searilzation
- std::string buff_to_send, buff_to_recv;
+ std::string buff_to_send;
stg.store_to_binary(buff_to_send);
int res = transport.invoke_async(command, buff_to_send, conn_id, [cb, command](int code, const std::string& buff, typename t_transport::connection_context& context)->bool
{
@@ -151,7 +151,7 @@ namespace epee
serialization::portable_storage stg;
out_struct.store(stg);
- std::string buff_to_send, buff_to_recv;
+ std::string buff_to_send;
stg.store_to_binary(buff_to_send);
int res = transport.notify(command, buff_to_send, conn_id);
diff --git a/contrib/epee/src/mlog.cpp b/contrib/epee/src/mlog.cpp
index 2ac3138f9..a3f38e677 100644
--- a/contrib/epee/src/mlog.cpp
+++ b/contrib/epee/src/mlog.cpp
@@ -91,7 +91,7 @@ static const char *get_default_categories(int level)
switch (level)
{
case 0:
- categories = "*:WARNING,net:FATAL,net.p2p:FATAL,net.cn:FATAL,global:INFO,verify:FATAL,stacktrace:INFO,logging:INFO";
+ categories = "*:WARNING,net:FATAL,net.p2p:FATAL,net.cn:FATAL,global:INFO,verify:FATAL,stacktrace:INFO,logging:INFO,msgwriter:INFO";
break;
case 1:
categories = "*:WARNING,global:INFO,stacktrace:INFO,logging:INFO,msgwriter:INFO";
diff --git a/external/db_drivers/liblmdb/lmdb.h b/external/db_drivers/liblmdb/lmdb.h
index a794c9f7d..0bca3eb74 100644
--- a/external/db_drivers/liblmdb/lmdb.h
+++ b/external/db_drivers/liblmdb/lmdb.h
@@ -311,6 +311,8 @@ typedef void (MDB_rel_func)(MDB_val *item, void *oldptr, void *newptr, void *rel
#define MDB_NORDAHEAD 0x800000
/** don't initialize malloc'd memory before writing to datafile */
#define MDB_NOMEMINIT 0x1000000
+ /** use the previous snapshot rather than the latest one */
+#define MDB_PREVSNAPSHOT 0x2000000
/** @} */
/** @defgroup mdb_dbi_open Database Flags
@@ -622,6 +624,12 @@ int mdb_env_create(MDB_env **env);
* caller is expected to overwrite all of the memory that was
* reserved in that case.
* This flag may be changed at any time using #mdb_env_set_flags().
+ * <li>#MDB_PREVSNAPSHOT
+ * Open the environment with the previous snapshot rather than the latest
+ * one. This loses the latest transaction, but may help work around some
+ * types of corruption. If opened with write access, this must be the
+ * only process using the environment. This flag is automatically reset
+ * after a write transaction is successfully committed.
* </ul>
* @param[in] mode The UNIX permissions to set on created files and semaphores.
* This parameter is ignored on Windows.
diff --git a/external/db_drivers/liblmdb/mdb.c b/external/db_drivers/liblmdb/mdb.c
index 3552bd2a9..377512ebe 100644
--- a/external/db_drivers/liblmdb/mdb.c
+++ b/external/db_drivers/liblmdb/mdb.c
@@ -1468,7 +1468,7 @@ static int mdb_page_merge(MDB_cursor *csrc, MDB_cursor *cdst);
static int mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata,
pgno_t newpgno, unsigned int nflags);
-static int mdb_env_read_header(MDB_env *env, MDB_meta *meta);
+static int mdb_env_read_header(MDB_env *env, int prev, MDB_meta *meta);
static MDB_meta *mdb_env_pick_meta(const MDB_env *env);
static int mdb_env_write_meta(MDB_txn *txn);
#ifdef MDB_USE_POSIX_MUTEX /* Drop unused excl arg */
@@ -3632,6 +3632,8 @@ done:
return MDB_SUCCESS;
}
+static int ESECT mdb_env_share_locks(MDB_env *env, int *excl);
+
int
mdb_txn_commit(MDB_txn *txn)
{
@@ -3854,6 +3856,15 @@ mdb_txn_commit(MDB_txn *txn)
if ((rc = mdb_env_write_meta(txn)))
goto fail;
end_mode = MDB_END_COMMITTED|MDB_END_UPDATE;
+ if (env->me_flags & MDB_PREVSNAPSHOT) {
+ if (!(env->me_flags & MDB_NOLOCK)) {
+ int excl;
+ rc = mdb_env_share_locks(env, &excl);
+ if (rc)
+ goto fail;
+ }
+ env->me_flags ^= MDB_PREVSNAPSHOT;
+ }
done:
mdb_txn_end(txn, end_mode);
@@ -3867,11 +3878,12 @@ fail:
/** Read the environment parameters of a DB environment before
* mapping it into memory.
* @param[in] env the environment handle
+ * @param[in] prev whether to read the backup meta page
* @param[out] meta address of where to store the meta information
* @return 0 on success, non-zero on failure.
*/
static int ESECT
-mdb_env_read_header(MDB_env *env, MDB_meta *meta)
+mdb_env_read_header(MDB_env *env, int prev, MDB_meta *meta)
{
MDB_metabuf pbuf;
MDB_page *p;
@@ -3922,7 +3934,7 @@ mdb_env_read_header(MDB_env *env, MDB_meta *meta)
return MDB_VERSION_MISMATCH;
}
- if (off == 0 || m->mm_txnid > meta->mm_txnid)
+ if (off == 0 || (prev ? m->mm_txnid < meta->mm_txnid : m->mm_txnid > meta->mm_txnid))
*meta = *m;
}
return 0;
@@ -4131,7 +4143,8 @@ static MDB_meta *
mdb_env_pick_meta(const MDB_env *env)
{
MDB_meta *const *metas = env->me_metas;
- return metas[ metas[0]->mm_txnid < metas[1]->mm_txnid ];
+ return metas[ (metas[0]->mm_txnid < metas[1]->mm_txnid) ^
+ ((env->me_flags & MDB_PREVSNAPSHOT) != 0) ];
}
int ESECT
@@ -4366,7 +4379,7 @@ mdb_fsize(HANDLE fd, mdb_size_t *size)
/** Further setup required for opening an LMDB environment
*/
static int ESECT
-mdb_env_open2(MDB_env *env)
+mdb_env_open2(MDB_env *env, int prev)
{
unsigned int flags = env->me_flags;
int i, newenv = 0, rc;
@@ -4429,7 +4442,7 @@ mdb_env_open2(MDB_env *env)
}
#endif
- if ((i = mdb_env_read_header(env, &meta)) != 0) {
+ if ((i = mdb_env_read_header(env, prev, &meta)) != 0) {
if (i != ENOENT)
return i;
DPUTS("new mdbenv");
@@ -4505,6 +4518,9 @@ mdb_env_open2(MDB_env *env)
#endif
env->me_maxpg = env->me_mapsize / env->me_psize;
+ if (env->me_txns)
+ env->me_txns->mti_txnid = meta.mm_txnid;
+
#if MDB_DEBUG
{
MDB_meta *meta = mdb_env_pick_meta(env);
@@ -4600,9 +4616,6 @@ static int ESECT
mdb_env_share_locks(MDB_env *env, int *excl)
{
int rc = 0;
- MDB_meta *meta = mdb_env_pick_meta(env);
-
- env->me_txns->mti_txnid = meta->mm_txnid;
#ifdef _WIN32
{
@@ -5056,7 +5069,7 @@ fail:
*/
#define CHANGEABLE (MDB_NOSYNC|MDB_NOMETASYNC|MDB_MAPASYNC|MDB_NOMEMINIT)
#define CHANGELESS (MDB_FIXEDMAP|MDB_NOSUBDIR|MDB_RDONLY| \
- MDB_WRITEMAP|MDB_NOTLS|MDB_NOLOCK|MDB_NORDAHEAD)
+ MDB_WRITEMAP|MDB_NOTLS|MDB_NOLOCK|MDB_NORDAHEAD|MDB_PREVSNAPSHOT)
#if VALID_FLAGS & PERSISTENT_FLAGS & (CHANGEABLE|CHANGELESS)
# error "Persistent DB flags & env flags overlap, but both go in mm_flags"
@@ -5178,9 +5191,13 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode
rc = mdb_env_setup_locks(env, lpath, mode, &excl);
if (rc)
goto leave;
+ if ((flags & MDB_PREVSNAPSHOT) && !excl) {
+ rc = EAGAIN;
+ goto leave;
+ }
}
- if ((rc = mdb_env_open2(env)) == MDB_SUCCESS) {
+ if ((rc = mdb_env_open2(env, flags & MDB_PREVSNAPSHOT)) == MDB_SUCCESS) {
if (flags & (MDB_RDONLY|MDB_WRITEMAP)) {
env->me_mfd = env->me_fd;
} else {
@@ -5206,7 +5223,7 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode
}
}
DPRINTF(("opened dbenv %p", (void *) env));
- if (excl > 0) {
+ if (excl > 0 && !(flags & MDB_PREVSNAPSHOT)) {
rc = mdb_env_share_locks(env, &excl);
if (rc)
goto leave;
diff --git a/external/db_drivers/liblmdb/mdb_copy.1 b/external/db_drivers/liblmdb/mdb_copy.1
index 1e2a97694..401e47abd 100644
--- a/external/db_drivers/liblmdb/mdb_copy.1
+++ b/external/db_drivers/liblmdb/mdb_copy.1
@@ -11,6 +11,8 @@ mdb_copy \- LMDB environment copy tool
.BR \-c ]
[\c
.BR \-n ]
+[\c
+.BR \-v ]
.B srcpath
[\c
.BR dstpath ]
@@ -39,6 +41,10 @@ slow down the backup process as it is more CPU-intensive.
.TP
.BR \-n
Open LDMB environment(s) which do not use subdirectories.
+.TP
+.BR \-v
+Use the previous environment state instead of the latest state.
+This may be useful if the latest state has been corrupted.
.SH DIAGNOSTICS
Exit status is zero if no errors occur.
diff --git a/external/db_drivers/liblmdb/mdb_copy.c b/external/db_drivers/liblmdb/mdb_copy.c
index f37ccbcc2..95a6e7130 100644
--- a/external/db_drivers/liblmdb/mdb_copy.c
+++ b/external/db_drivers/liblmdb/mdb_copy.c
@@ -38,6 +38,8 @@ int main(int argc,char * argv[])
for (; argc > 1 && argv[1][0] == '-'; argc--, argv++) {
if (argv[1][1] == 'n' && argv[1][2] == '\0')
flags |= MDB_NOSUBDIR;
+ else if (argv[1][1] == 'v' && argv[1][2] == '\0')
+ flags |= MDB_PREVSNAPSHOT;
else if (argv[1][1] == 'c' && argv[1][2] == '\0')
cpflags |= MDB_CP_COMPACT;
else if (argv[1][1] == 'V' && argv[1][2] == '\0') {
@@ -48,7 +50,7 @@ int main(int argc,char * argv[])
}
if (argc<2 || argc>3) {
- fprintf(stderr, "usage: %s [-V] [-c] [-n] srcpath [dstpath]\n", progname);
+ fprintf(stderr, "usage: %s [-V] [-c] [-n] [-v] srcpath [dstpath]\n", progname);
exit(EXIT_FAILURE);
}
diff --git a/external/db_drivers/liblmdb/mdb_dump.1 b/external/db_drivers/liblmdb/mdb_dump.1
index 5a647ba2e..a25fb92e9 100644
--- a/external/db_drivers/liblmdb/mdb_dump.1
+++ b/external/db_drivers/liblmdb/mdb_dump.1
@@ -14,6 +14,8 @@ mdb_dump \- LMDB environment export tool
[\c
.BR \-n ]
[\c
+.BR \-v ]
+[\c
.BR \-p ]
[\c
.BR \-a \ |
@@ -42,6 +44,10 @@ names will be listed, no data will be output.
.BR \-n
Dump an LMDB database which does not use subdirectories.
.TP
+.BR \-v
+Use the previous environment state instead of the latest state.
+This may be useful if the latest state has been corrupted.
+.TP
.BR \-p
If characters in either the key or data items are printing characters (as
defined by isprint(3)), output them directly. This option permits users to
diff --git a/external/db_drivers/liblmdb/mdb_dump.c b/external/db_drivers/liblmdb/mdb_dump.c
index 72a469052..7a42bc0b6 100644
--- a/external/db_drivers/liblmdb/mdb_dump.c
+++ b/external/db_drivers/liblmdb/mdb_dump.c
@@ -164,7 +164,7 @@ static int dumpit(MDB_txn *txn, MDB_dbi dbi, char *name)
static void usage(char *prog)
{
- fprintf(stderr, "usage: %s [-V] [-f output] [-l] [-n] [-p] [-a|-s subdb] dbpath\n", prog);
+ fprintf(stderr, "usage: %s [-V] [-f output] [-l] [-n] [-p] [-v] [-a|-s subdb] dbpath\n", prog);
exit(EXIT_FAILURE);
}
@@ -188,6 +188,7 @@ int main(int argc, char *argv[])
* -n: use NOSUBDIR flag on env_open
* -p: use printable characters
* -f: write to file instead of stdout
+ * -v: use previous snapshot
* -V: print version and exit
* (default) dump only the main DB
*/
@@ -215,6 +216,9 @@ int main(int argc, char *argv[])
case 'n':
envflags |= MDB_NOSUBDIR;
break;
+ case 'v':
+ envflags |= MDB_PREVSNAPSHOT;
+ break;
case 'p':
mode |= PRINT;
break;
diff --git a/external/db_drivers/liblmdb/mdb_stat.1 b/external/db_drivers/liblmdb/mdb_stat.1
index 351c01757..bf49bd3bd 100644
--- a/external/db_drivers/liblmdb/mdb_stat.1
+++ b/external/db_drivers/liblmdb/mdb_stat.1
@@ -14,6 +14,8 @@ mdb_stat \- LMDB environment status tool
[\c
.BR \-n ]
[\c
+.BR \-v ]
+[\c
.BR \-r [ r ]]
[\c
.BR \-a \ |
@@ -39,6 +41,10 @@ If \fB\-fff\fP is given, display the full list of page IDs in the freelist.
.BR \-n
Display the status of an LMDB database which does not use subdirectories.
.TP
+.BR \-v
+Use the previous environment state instead of the latest state.
+This may be useful if the latest state has been corrupted.
+.TP
.BR \-r
Display information about the environment reader table.
Shows the process ID, thread ID, and transaction ID for each active
diff --git a/external/db_drivers/liblmdb/mdb_stat.c b/external/db_drivers/liblmdb/mdb_stat.c
index b785e7acf..30ec81fea 100644
--- a/external/db_drivers/liblmdb/mdb_stat.c
+++ b/external/db_drivers/liblmdb/mdb_stat.c
@@ -46,7 +46,7 @@ static void prstat(MDB_stat *ms)
static void usage(char *prog)
{
- fprintf(stderr, "usage: %s [-V] [-n] [-e] [-r[r]] [-f[f[f]]] [-a|-s subdb] dbpath\n", prog);
+ fprintf(stderr, "usage: %s [-V] [-n] [-e] [-r[r]] [-f[f[f]]] [-v] [-a|-s subdb] dbpath\n", prog);
exit(EXIT_FAILURE);
}
@@ -73,6 +73,7 @@ int main(int argc, char *argv[])
* -f: print freelist info
* -r: print reader info
* -n: use NOSUBDIR flag on env_open
+ * -v: use previous snapshot
* -V: print version and exit
* (default) print stat of only the main DB
*/
@@ -96,6 +97,9 @@ int main(int argc, char *argv[])
case 'n':
envflags |= MDB_NOSUBDIR;
break;
+ case 'v':
+ envflags |= MDB_PREVSNAPSHOT;
+ break;
case 'r':
rdrinfo++;
break;
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d83242a3c..e473c2984 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -120,6 +120,10 @@ if(NOT IOS)
add_subdirectory(blockchain_utilities)
endif()
+if(CMAKE_BUILD_TYPE STREQUAL Debug)
+ add_subdirectory(debug_utilities)
+endif()
+
if(PER_BLOCK_CHECKPOINT)
add_subdirectory(blocks)
endif()
diff --git a/src/blockchain_utilities/CMakeLists.txt b/src/blockchain_utilities/CMakeLists.txt
index 628c037b3..ffdaad4af 100644
--- a/src/blockchain_utilities/CMakeLists.txt
+++ b/src/blockchain_utilities/CMakeLists.txt
@@ -67,11 +67,6 @@ monero_private_headers(blockchain_export
${blockchain_export_private_headers})
-set(cn_deserialize_sources
- cn_deserialize.cpp
- )
-
-
monero_add_executable(blockchain_import
${blockchain_import_sources}
${blockchain_import_private_headers}
@@ -122,21 +117,3 @@ set_property(TARGET blockchain_export
PROPERTY
OUTPUT_NAME "monero-blockchain-export")
-monero_add_executable(cn_deserialize
- ${cn_deserialize_sources}
- ${cn_deserialize_private_headers})
-
-target_link_libraries(cn_deserialize
- LINK_PRIVATE
- cryptonote_core
- blockchain_db
- p2p
- epee
- ${CMAKE_THREAD_LIBS_INIT})
-
-add_dependencies(cn_deserialize
- version)
-set_property(TARGET cn_deserialize
- PROPERTY
- OUTPUT_NAME "monero-utils-deserialize")
-
diff --git a/src/common/perf_timer.h b/src/common/perf_timer.h
index 56662ff24..bc8e05800 100644
--- a/src/common/perf_timer.h
+++ b/src/common/perf_timer.h
@@ -46,9 +46,9 @@ extern __thread std::vector<PerformanceTimer*> *performance_timers;
class PerformanceTimer
{
public:
- PerformanceTimer(const std::string &s, el::Level l = el::Level::Debug): name(s), level(l), started(false)
+ PerformanceTimer(const std::string &s, uint64_t unit, el::Level l = el::Level::Debug): name(s), unit(unit), level(l), started(false)
{
- ticks = epee::misc_utils::get_tick_count();
+ ticks = epee::misc_utils::get_ns_count();
if (!performance_timers)
{
MLOG(level, "PERF ----------");
@@ -69,9 +69,9 @@ public:
~PerformanceTimer()
{
performance_timers->pop_back();
- ticks = epee::misc_utils::get_tick_count() - ticks;
+ ticks = epee::misc_utils::get_ns_count() - ticks;
char s[12];
- snprintf(s, sizeof(s), "%8llu ", (unsigned long long)ticks);
+ snprintf(s, sizeof(s), "%8llu ", (unsigned long long)ticks / (1000000000 / unit));
MLOG(level, "PERF " << s << std::string(performance_timers->size() * 2, ' ') << " " << name);
if (performance_timers->empty())
{
@@ -82,6 +82,7 @@ public:
private:
std::string name;
+ uint64_t unit;
el::Level level;
uint64_t ticks;
bool started;
@@ -89,7 +90,9 @@ private:
void set_performance_timer_log_level(el::Level level);
-#define PERF_TIMER(name) tools::PerformanceTimer pt_##name(#name, tools::performance_timer_log_level)
-#define PERF_TIMER_L(name, l) tools::PerformanceTimer pt_##name(#name, l)
+#define PERF_TIMER_UNIT(name, unit) tools::PerformanceTimer pt_##name(#name, unit, tools::performance_timer_log_level)
+#define PERF_TIMER_UNIT_L(name, unit, l) tools::PerformanceTimer pt_##name(#name, unit, l)
+#define PERF_TIMER(name) PERF_TIMER_UNIT(name, 1000)
+#define PERF_TIMER_L(name, l) PERF_TIMER_UNIT_L(name, 1000, l)
}
diff --git a/src/common/scoped_message_writer.h b/src/common/scoped_message_writer.h
index e31f8f0b2..8fc98d2b0 100644
--- a/src/common/scoped_message_writer.h
+++ b/src/common/scoped_message_writer.h
@@ -31,6 +31,14 @@
#include "misc_log_ex.h"
#include <iostream>
+#ifdef HAVE_READLINE
+ #include "readline_buffer.h"
+ #define PAUSE_READLINE() \
+ rdln::suspend_readline pause_readline;
+#else
+ #define PAUSE_READLINE()
+#endif
+
namespace tools
{
@@ -99,6 +107,7 @@ public:
}
else
{
+ PAUSE_READLINE();
set_console_color(m_color, m_bright);
std::cout << m_oss.str();
epee::reset_console_color();
@@ -108,9 +117,9 @@ public:
}
};
-inline scoped_message_writer success_msg_writer()
+inline scoped_message_writer success_msg_writer(bool color = true)
{
- return scoped_message_writer(epee::console_color_green, false, std::string(), el::Level::Info);
+ return scoped_message_writer(color ? epee::console_color_green : epee::console_color_default, false, std::string(), el::Level::Info);
}
inline scoped_message_writer msg_writer(epee::console_colors color = epee::console_color_default)
diff --git a/src/cryptonote_basic/cryptonote_basic_impl.h b/src/cryptonote_basic/cryptonote_basic_impl.h
index 9838fcb47..7a2259b32 100644
--- a/src/cryptonote_basic/cryptonote_basic_impl.h
+++ b/src/cryptonote_basic/cryptonote_basic_impl.h
@@ -69,7 +69,7 @@ namespace cryptonote {
namespace
{
- std::string return_first_address(const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid)
+ inline std::string return_first_address(const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid)
{
if (addresses.empty())
return {};
diff --git a/src/cryptonote_basic/difficulty.h b/src/cryptonote_basic/difficulty.h
index aed6cb289..aeb1c030d 100644
--- a/src/cryptonote_basic/difficulty.h
+++ b/src/cryptonote_basic/difficulty.h
@@ -42,9 +42,9 @@ namespace cryptonote
/**
* @brief checks if a hash fits the given difficulty
*
- * The hash passes if (hash * difficulty) < 2^192.
+ * The hash passes if (hash * difficulty) < 2^256.
* Phrased differently, if (hash * difficulty) fits without overflow into
- * the least significant 192 bits of the 256 bit multiplication result.
+ * the least significant 256 bits of the 320 bit multiplication result.
*
* @param hash the hash to check
* @param difficulty the difficulty to check against
diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp
index 9248e2e1d..3c5811d61 100644
--- a/src/cryptonote_basic/miner.cpp
+++ b/src/cryptonote_basic/miner.cpp
@@ -382,7 +382,7 @@ namespace cryptonote
boost::thread::attributes attrs;
attrs.set_stack_size(THREAD_STACK_SIZE);
- start(m_mine_address, m_threads_total, attrs, get_is_background_mining_enabled());
+ start(m_mine_address, m_threads_total, attrs, get_is_background_mining_enabled(), get_ignore_battery());
}
}
//-----------------------------------------------------------------------------------------------------
@@ -412,8 +412,8 @@ namespace cryptonote
bool miner::worker_thread()
{
uint32_t th_local_index = boost::interprocess::ipcdetail::atomic_inc32(&m_thread_index);
- MGINFO("Miner thread was started ["<< th_local_index << "]");
MLOG_SET_THREAD_NAME(std::string("[miner ") + std::to_string(th_local_index) + "]");
+ MGINFO("Miner thread was started ["<< th_local_index << "]");
uint32_t nonce = m_starter_nonce + th_local_index;
uint64_t height = 0;
difficulty_type local_diff = 0;
diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h
index 8dbf1b53b..fd45c0822 100644
--- a/src/cryptonote_config.h
+++ b/src/cryptonote_config.h
@@ -89,7 +89,7 @@
#define BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT 10000 //by default, blocks ids count in synchronizing
-#define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT 200 //by default, blocks count in blocks downloading
+#define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT 20 //by default, blocks count in blocks downloading
#define CRYPTONOTE_PROTOCOL_HOP_RELAX_COUNT 3 //value of hop, after which we use only announce of new block
#define CRYPTONOTE_MEMPOOL_TX_LIVETIME 86400 //seconds, one day
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 404321e0f..61ddff3d0 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -125,8 +125,8 @@ static const uint64_t testnet_hard_fork_version_1_till = 624633;
//------------------------------------------------------------------
Blockchain::Blockchain(tx_memory_pool& tx_pool) :
- m_db(), m_tx_pool(tx_pool), m_hardfork(NULL), m_timestamps_and_difficulties_height(0), m_current_block_cumul_sz_limit(0), m_is_in_checkpoint_zone(false),
- m_is_blockchain_storing(false), m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_blocks_per_sync(1), m_db_sync_mode(db_async), m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_cancel(false)
+ m_db(), m_tx_pool(tx_pool), m_hardfork(NULL), m_timestamps_and_difficulties_height(0), m_current_block_cumul_sz_limit(0),
+ m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_blocks_per_sync(1), m_db_sync_mode(db_async), m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_cancel(false)
{
LOG_PRINT_L3("Blockchain::" << __func__);
}
@@ -1353,7 +1353,6 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
}
// Check the block's hash against the difficulty target for its alt chain
- m_is_in_checkpoint_zone = false;
difficulty_type current_diff = get_next_difficulty_for_alternative_chain(alt_chain, bei);
CHECK_AND_ASSERT_MES(current_diff, false, "!!!!!!! DIFFICULTY OVERHEAD !!!!!!!");
crypto::hash proof_of_work = null_hash;
@@ -1428,7 +1427,9 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
{
//block orphaned
bvc.m_marked_as_orphaned = true;
- MERROR_VER("Block recognized as orphaned and rejected, id = " << id);
+ MERROR_VER("Block recognized as orphaned and rejected, id = " << id << ", height " << block_height
+ << ", parent in alt " << (it_prev != m_alternative_chains.end()) << ", parent in main " << parent_in_main
+ << " (parent " << b.prev_id << ", current top " << get_tail_id() << ", chain height " << get_current_blockchain_height() << ")");
}
return true;
@@ -2499,7 +2500,6 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
assert(it != m_check_txin_table.end());
}
- uint64_t t_t1 = 0;
std::vector<std::vector<rct::ctkey>> pubkeys(tx.vin.size());
std::vector < uint64_t > results;
results.resize(tx.vin.size(), 0);
@@ -2633,7 +2633,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
if (failed)
{
- MERROR_VER("Failed to check ring signatures!, t_loop: " << t_t1);
+ MERROR_VER("Failed to check ring signatures!");
return false;
}
}
@@ -2782,12 +2782,6 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
//------------------------------------------------------------------
void Blockchain::check_ring_signature(const crypto::hash &tx_prefix_hash, const crypto::key_image &key_image, const std::vector<rct::ctkey> &pubkeys, const std::vector<crypto::signature>& sig, uint64_t &result)
{
- if (m_is_in_checkpoint_zone)
- {
- result = true;
- return;
- }
-
std::vector<const crypto::public_key *> p_output_keys;
for (auto &key : pubkeys)
{
@@ -3883,17 +3877,17 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list<block_complete_e
offset_map[in_to_key.amount].push_back(offset);
}
-
- // sort and remove duplicate absolute_offsets in offset_map
- for (auto &offsets : offset_map)
- {
- std::sort(offsets.second.begin(), offsets.second.end());
- auto last = std::unique(offsets.second.begin(), offsets.second.end());
- offsets.second.erase(last, offsets.second.end());
- }
}
}
+ // sort and remove duplicate absolute_offsets in offset_map
+ for (auto &offsets : offset_map)
+ {
+ std::sort(offsets.second.begin(), offsets.second.end());
+ auto last = std::unique(offsets.second.begin(), offsets.second.end());
+ offsets.second.erase(last, offsets.second.end());
+ }
+
// [output] stores all transactions for each tx_out_index::hash found
std::vector<std::unordered_map<crypto::hash, cryptonote::transaction>> transactions(amounts.size());
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index aa61dc034..7137f50a7 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -585,7 +585,7 @@ namespace cryptonote
*
* @return true if Blockchain is having the chain stored currently, else false
*/
- bool is_storing_blockchain()const{return m_is_blockchain_storing;}
+ bool is_storing_blockchain()const{return false;}
/**
* @brief gets the difficulty of the block with a given height
@@ -943,8 +943,6 @@ namespace cryptonote
checkpoints m_checkpoints;
- std::atomic<bool> m_is_in_checkpoint_zone;
- std::atomic<bool> m_is_blockchain_storing;
bool m_enforce_dns_checkpoints;
HardFork *m_hardfork;
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 13e5badd1..62c536ab8 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -1232,6 +1232,16 @@ namespace cryptonote
return true;
}
//-----------------------------------------------------------------------------------------------
+ uint8_t core::get_ideal_hard_fork_version(uint64_t height) const
+ {
+ return get_blockchain_storage().get_ideal_hard_fork_version(height);
+ }
+ //-----------------------------------------------------------------------------------------------
+ uint8_t core::get_hard_fork_version(uint64_t height) const
+ {
+ return get_blockchain_storage().get_hard_fork_version(height);
+ }
+ //-----------------------------------------------------------------------------------------------
bool core::check_updates()
{
static const char software[] = "monero";
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index 171c3cb98..63d3cd16d 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -621,6 +621,20 @@ namespace cryptonote
uint64_t get_target_blockchain_height() const;
/**
+ * @brief return the ideal hard fork version for a given block height
+ *
+ * @return what it says above
+ */
+ uint8_t get_ideal_hard_fork_version(uint64_t height) const;
+
+ /**
+ * @brief return the hard fork version for a given block height
+ *
+ * @return what it says above
+ */
+ uint8_t get_hard_fork_version(uint64_t height) const;
+
+ /**
* @brief gets start_time
*
*/
diff --git a/src/cryptonote_protocol/block_queue.cpp b/src/cryptonote_protocol/block_queue.cpp
index 610637637..4f760582b 100644
--- a/src/cryptonote_protocol/block_queue.cpp
+++ b/src/cryptonote_protocol/block_queue.cpp
@@ -189,6 +189,8 @@ std::pair<uint64_t, uint64_t> block_queue::reserve_span(uint64_t first_block_hei
++i;
++span_length;
}
+ if (span_length == 0)
+ return std::make_pair(0, 0);
MDEBUG("Reserving span " << span_start_height << " - " << (span_start_height + span_length - 1) << " for " << connection_id);
add_blocks(span_start_height, span_length, connection_id, time);
set_span_hashes(span_start_height, connection_id, hashes);
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h
index dcee03f66..f30aebf3a 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h
@@ -130,6 +130,8 @@ namespace cryptonote
size_t get_synchronizing_connections_count();
bool on_connection_synchronized();
bool should_download_next_span(cryptonote_connection_context& context) const;
+ void drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans);
+
t_core& m_core;
nodetool::p2p_endpoint_stub<connection_context> m_p2p_stub;
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index b5a307208..5b3b059a4 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -209,10 +209,10 @@ namespace cryptonote
cnx.support_flags = support_flags;
cnx.recv_count = cntxt.m_recv_cnt;
- cnx.recv_idle_time = timestamp - cntxt.m_last_recv;
+ cnx.recv_idle_time = timestamp - std::max(cntxt.m_started, cntxt.m_last_recv);
cnx.send_count = cntxt.m_send_cnt;
- cnx.send_idle_time = timestamp - cntxt.m_last_send;
+ cnx.send_idle_time = timestamp - std::max(cntxt.m_started, cntxt.m_last_send);
cnx.state = get_protocol_state_string(cntxt.m_state);
@@ -259,10 +259,10 @@ namespace cryptonote
return true;
// from v6, if the peer advertises a top block version, reject if it's not what it should be (will only work if no voting)
- const uint8_t version = m_core.get_blockchain_storage().get_ideal_hard_fork_version(hshd.current_height - 1);
+ const uint8_t version = m_core.get_ideal_hard_fork_version(hshd.current_height - 1);
if (version >= 6 && version != hshd.top_version)
{
- LOG_DEBUG_CC(context, "Ignoring due to wrong top version (" << hshd.top_version << ", expected " << version);
+ LOG_DEBUG_CC(context, "Ignoring due to wrong top version " << (unsigned)hshd.top_version << ", expected " << (unsigned)version);
return false;
}
@@ -308,7 +308,7 @@ namespace cryptonote
bool t_cryptonote_protocol_handler<t_core>::get_payload_sync_data(CORE_SYNC_DATA& hshd)
{
m_core.get_blockchain_top(hshd.current_height, hshd.top_id);
- hshd.top_version = m_core.get_blockchain_storage().get_hard_fork_version(hshd.current_height);
+ hshd.top_version = m_core.get_hard_fork_version(hshd.current_height);
hshd.current_height +=1;
return true;
}
@@ -344,10 +344,9 @@ namespace cryptonote
if(tvc.m_verifivation_failed)
{
LOG_PRINT_CCONTEXT_L1("Block verification failed: transaction verification failed, dropping connection");
- m_p2p->drop_connection(context);
+ drop_connection(context, false, false);
m_core.cleanup_handle_incoming_blocks();
m_core.resume_mine();
- m_block_queue.flush_spans(context.m_connection_id);
return 1;
}
}
@@ -359,9 +358,7 @@ namespace cryptonote
if(bvc.m_verifivation_failed)
{
LOG_PRINT_CCONTEXT_L0("Block verification failed, dropping connection");
- m_p2p->drop_connection(context);
- m_p2p->add_host_fail(context.m_remote_address);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, true, false);
return 1;
}
if(bvc.m_added_to_main_chain)
@@ -414,8 +411,7 @@ namespace cryptonote
<< ", dropping connection"
);
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
m_core.resume_mine();
return 1;
}
@@ -448,8 +444,7 @@ namespace cryptonote
<< ", dropping connection"
);
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
m_core.resume_mine();
return 1;
}
@@ -463,8 +458,7 @@ namespace cryptonote
<< ", dropping connection"
);
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
m_core.resume_mine();
return 1;
}
@@ -488,8 +482,7 @@ namespace cryptonote
<< "dropping connection"
);
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
m_core.resume_mine();
return 1;
}
@@ -506,8 +499,7 @@ namespace cryptonote
if(!m_core.handle_incoming_tx(tx_blob, tvc, true, true, false) || tvc.m_verifivation_failed)
{
LOG_PRINT_CCONTEXT_L1("Block verification failed: transaction verification failed, dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
m_core.resume_mine();
return 1;
}
@@ -529,8 +521,7 @@ namespace cryptonote
<< ", dropping connection"
);
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
m_core.resume_mine();
return 1;
}
@@ -550,8 +541,7 @@ namespace cryptonote
<< ", dropping connection"
);
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
m_core.resume_mine();
return 1;
}
@@ -628,9 +618,7 @@ namespace cryptonote
if( bvc.m_verifivation_failed )
{
LOG_PRINT_CCONTEXT_L0("Block verification failed, dropping connection");
- m_p2p->drop_connection(context);
- m_p2p->add_host_fail(context.m_remote_address);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, true, false);
return 1;
}
if( bvc.m_added_to_main_chain )
@@ -663,8 +651,7 @@ namespace cryptonote
);
m_core.resume_mine();
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
@@ -684,8 +671,7 @@ namespace cryptonote
if (!m_core.get_block_by_hash(arg.block_hash, b))
{
LOG_ERROR_CCONTEXT("failed to find block: " << arg.block_hash << ", dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
@@ -712,8 +698,7 @@ namespace cryptonote
<< ", dropping connection"
);
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
}
@@ -724,16 +709,14 @@ namespace cryptonote
{
LOG_ERROR_CCONTEXT("Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX, "
<< "failed to get requested transactions");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
if (!missed.empty() || txs.size() != txids.size())
{
LOG_ERROR_CCONTEXT("Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX, "
<< missed.size() << " requested transactions not found" << ", dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
@@ -776,8 +759,7 @@ namespace cryptonote
if(tvc.m_verifivation_failed)
{
LOG_PRINT_CCONTEXT_L1("Tx verification failed, dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
if(tvc.m_should_be_relayed)
@@ -803,8 +785,7 @@ namespace cryptonote
if(!m_core.handle_get_objects(arg, rsp, context))
{
LOG_ERROR_CCONTEXT("failed to handle request NOTIFY_REQUEST_GET_OBJECTS, dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
LOG_PRINT_CCONTEXT_L2("-->>NOTIFY_RESPONSE_GET_OBJECTS: blocks.size()=" << rsp.blocks.size() << ", txs.size()=" << rsp.txs.size()
@@ -871,8 +852,7 @@ namespace cryptonote
{
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_HAVE_OBJECTS: arg.m_current_blockchain_height=" << arg.current_blockchain_height
<< " < m_last_response_height=" << context.m_last_response_height << ", dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
@@ -894,16 +874,14 @@ namespace cryptonote
{
LOG_ERROR_CCONTEXT("sent wrong block: failed to parse and validate block: "
<< epee::string_tools::buff_to_hex_nodelimer(block_entry.block) << ", dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
if (b.miner_tx.vin.size() != 1 || b.miner_tx.vin.front().type() != typeid(txin_gen))
{
LOG_ERROR_CCONTEXT("sent wrong block: block: miner tx does not have exactly one txin_gen input"
<< epee::string_tools::buff_to_hex_nodelimer(block_entry.block) << ", dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
if (start_height == std::numeric_limits<uint64_t>::max())
@@ -915,16 +893,14 @@ namespace cryptonote
{
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(block_entry.block))
<< " wasn't requested, dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
if(b.tx_hashes.size() != block_entry.txs.size())
{
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(block_entry.block))
<< ", tx_hashes.size()=" << b.tx_hashes.size() << " mismatch with block_complete_entry.m_txs.size()=" << block_entry.txs.size() << ", dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
@@ -936,8 +912,7 @@ namespace cryptonote
{
MERROR("returned not all requested objects (context.m_requested_objects.size()="
<< context.m_requested_objects.size() << "), dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
@@ -959,6 +934,8 @@ namespace cryptonote
MDEBUG(context << " adding span: " << arg.blocks.size() << " at height " << start_height << ", " << dt.total_microseconds()/1e6 << " seconds, " << (rate/1e3) << " kB/s, size now " << (m_block_queue.get_data_size() + blocks_size) / 1048576.f << " MB");
m_block_queue.add_blocks(start_height, arg.blocks, context.m_connection_id, rate, blocks_size);
+ context.m_last_known_hash = cryptonote::get_blob_hash(arg.blocks.back().block);
+
if (m_core.get_test_drop_download() && m_core.get_test_drop_download_height()) { // DISCARD BLOCKS for testing
// We try to lock the sync lock. If we can, it means no other thread is
@@ -990,6 +967,43 @@ namespace cryptonote
MDEBUG(context << " next span in the queue has blocks " << start_height << "-" << (start_height + blocks.size() - 1)
<< ", we need " << previous_height);
+
+ block new_block;
+ if (!parse_and_validate_block_from_blob(blocks.front().block, new_block))
+ {
+ MERROR("Failed to parse block, but it should already have been parsed");
+ break;
+ }
+ bool parent_known = m_core.have_block(new_block.prev_id);
+ if (!parent_known)
+ {
+ // it could be:
+ // - later in the current chain
+ // - later in an alt chain
+ // - orphan
+ // if it was requested, then it'll be resolved later, otherwise it's an orphan
+ bool parent_requested = false;
+ m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool{
+ if (context.m_requested_objects.find(new_block.prev_id) != context.m_requested_objects.end())
+ {
+ parent_requested = true;
+ return false;
+ }
+ return true;
+ });
+ if (!parent_requested)
+ {
+ LOG_ERROR_CCONTEXT("Got block with unknown parent which was not requested - dropping connection");
+ // in case the peer had dropped beforehand, remove the span anyway so other threads can wake up and get it
+ m_block_queue.remove_spans(span_connection_id, start_height);
+ return 1;
+ }
+
+ // parent was requested, so we wait for it to be retrieved
+ MINFO(context << " parent was requested, we'll get back to it");
+ break;
+ }
+
const boost::posix_time::ptime start = boost::posix_time::microsec_clock::universal_time();
m_core.prepare_handle_incoming_blocks(blocks);
@@ -1017,8 +1031,7 @@ namespace cryptonote
if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
LOG_ERROR_CCONTEXT("transaction verification failed on NOTIFY_RESPONSE_GET_OBJECTS, tx_id = "
<< epee::string_tools::pod_to_hex(get_blob_hash(*it)) << ", dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id, true);
+ drop_connection(context, false, true);
return true;
}))
LOG_ERROR_CCONTEXT("span connection id not found");
@@ -1043,9 +1056,7 @@ namespace cryptonote
{
if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
LOG_PRINT_CCONTEXT_L1("Block verification failed, dropping connection");
- m_p2p->drop_connection(context);
- m_p2p->add_host_fail(context.m_remote_address);
- m_block_queue.flush_spans(context.m_connection_id, true);
+ drop_connection(context, true, true);
return true;
}))
LOG_ERROR_CCONTEXT("span connection id not found");
@@ -1059,9 +1070,7 @@ namespace cryptonote
{
if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
LOG_PRINT_CCONTEXT_L1("Block received at sync phase was marked as orphaned, dropping connection");
- m_p2p->drop_connection(context);
- m_p2p->add_host_fail(context.m_remote_address);
- m_block_queue.flush_spans(context.m_connection_id, true);
+ drop_connection(context, true, true);
return true;
}))
LOG_ERROR_CCONTEXT("span connection id not found");
@@ -1111,8 +1120,7 @@ skip:
if (!request_missing_objects(context, true, force_next_span))
{
LOG_ERROR_CCONTEXT("Failed to request missing objects, dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
return 1;
@@ -1132,8 +1140,7 @@ skip:
if(!m_core.find_blockchain_supplement(arg.block_ids, r))
{
LOG_ERROR_CCONTEXT("Failed to handle NOTIFY_REQUEST_CHAIN.");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
LOG_PRINT_CCONTEXT_L2("-->>NOTIFY_RESPONSE_CHAIN_ENTRY: m_start_height=" << r.start_height << ", m_total_height=" << r.total_height << ", m_block_ids.size()=" << r.m_block_ids.size());
@@ -1462,9 +1469,7 @@ skip:
if(!arg.m_block_ids.size())
{
LOG_ERROR_CCONTEXT("sent empty m_block_ids, dropping connection");
- m_p2p->drop_connection(context);
- m_p2p->add_host_fail(context.m_remote_address);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, true, false);
return 1;
}
@@ -1475,8 +1480,7 @@ skip:
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_CHAIN_ENTRY, with m_total_height=" << arg.total_height
<< ", m_start_height=" << arg.start_height
<< ", m_block_ids.size()=" << arg.m_block_ids.size());
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
@@ -1484,13 +1488,11 @@ skip:
{
context.m_needed_objects.push_back(bl_id);
}
- context.m_last_known_hash = context.m_needed_objects.back();
if (!request_missing_objects(context, false))
{
LOG_ERROR_CCONTEXT("Failed to request missing objects, dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
return 1;
@@ -1546,6 +1548,29 @@ skip:
m_core.on_transaction_relayed(*tx_blob_it);
return relay_post_notify<NOTIFY_NEW_TRANSACTIONS>(arg, exclude_context);
}
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
+ void t_cryptonote_protocol_handler<t_core>::drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans)
+ {
+ if (add_fail)
+ m_p2p->add_host_fail(context.m_remote_address);
+ m_p2p->drop_connection(context);
+
+ uint64_t target = 0;
+ m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags) {
+ if (cntxt.m_state >= cryptonote_connection_context::state_synchronizing && cntxt.m_connection_id != context.m_connection_id)
+ target = std::max(target, cntxt.m_remote_blockchain_height);
+ return true;
+ });
+ const uint64_t previous_target = m_core.get_target_blockchain_height();
+ if (target < previous_target)
+ {
+ MINFO("Target height decreasing from " << previous_target << " to " << target);
+ m_core.set_target_blockchain_height(target);
+ }
+
+ m_block_queue.flush_spans(context.m_connection_id, flush_all_spans);
+ }
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
diff --git a/src/debug_utilities/CMakeLists.txt b/src/debug_utilities/CMakeLists.txt
new file mode 100644
index 000000000..99198dc57
--- /dev/null
+++ b/src/debug_utilities/CMakeLists.txt
@@ -0,0 +1,73 @@
+# Copyright (c) 2014-2017, The Monero Project
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are
+# permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this list of
+# conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice, this list
+# of conditions and the following disclaimer in the documentation and/or other
+# materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its contributors may be
+# used to endorse or promote products derived from this software without specific
+# prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+set(cn_deserialize_sources
+ cn_deserialize.cpp
+ )
+
+monero_add_executable(cn_deserialize
+ ${cn_deserialize_sources}
+ ${cn_deserialize_private_headers})
+
+target_link_libraries(cn_deserialize
+ LINK_PRIVATE
+ cryptonote_core
+ blockchain_db
+ p2p
+ epee
+ ${CMAKE_THREAD_LIBS_INIT})
+
+add_dependencies(cn_deserialize
+ version)
+set_property(TARGET cn_deserialize
+ PROPERTY
+ OUTPUT_NAME "monero-utils-deserialize")
+
+
+set(object_sizes_sources
+ object_sizes.cpp
+ )
+
+monero_add_executable(object_sizes
+ ${object_sizes_sources}
+ ${object_sizes_private_headers})
+
+target_link_libraries(object_sizes
+ LINK_PRIVATE
+ cryptonote_core
+ blockchain_db
+ p2p
+ epee
+ ${CMAKE_THREAD_LIBS_INIT})
+
+add_dependencies(object_sizes
+ version)
+set_property(TARGET object_sizes
+ PROPERTY
+ OUTPUT_NAME "monero-utils-object-sizes")
+
diff --git a/src/blockchain_utilities/cn_deserialize.cpp b/src/debug_utilities/cn_deserialize.cpp
index b178e4e03..a1b569554 100644
--- a/src/blockchain_utilities/cn_deserialize.cpp
+++ b/src/debug_utilities/cn_deserialize.cpp
@@ -29,12 +29,11 @@
#include "cryptonote_basic/cryptonote_basic.h"
#include "cryptonote_basic/tx_extra.h"
#include "cryptonote_core/blockchain.h"
-#include "blockchain_utilities.h"
#include "common/command_line.h"
#include "version.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
-#define MONERO_DEFAULT_LOG_CATEGORY "bcutil"
+#define MONERO_DEFAULT_LOG_CATEGORY "debugtools.deserialize"
namespace po = boost::program_options;
using namespace epee;
diff --git a/src/debug_utilities/object_sizes.cpp b/src/debug_utilities/object_sizes.cpp
new file mode 100644
index 000000000..47ba5cf6c
--- /dev/null
+++ b/src/debug_utilities/object_sizes.cpp
@@ -0,0 +1,116 @@
+// Copyright (c) 2017, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <map>
+#include "cryptonote_basic/cryptonote_basic.h"
+#include "cryptonote_basic/tx_extra.h"
+#include "cryptonote_core/blockchain.h"
+#include "p2p/p2p_protocol_defs.h"
+#include "p2p/connection_basic.hpp"
+#include "p2p/net_peerlist.h"
+#include "p2p/net_node.h"
+#include "cryptonote_protocol/cryptonote_protocol_handler.h"
+#include "blockchain_db/lmdb/db_lmdb.h"
+#include "wallet/wallet2.h"
+#include "wallet/api/wallet.h"
+#include "wallet/api/transaction_info.h"
+#include "wallet/api/transaction_history.h"
+#include "wallet/api/unsigned_transaction.h"
+#include "wallet/api/pending_transaction.h"
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "debugtools.objectsizes"
+
+class size_logger
+{
+public:
+ ~size_logger()
+ {
+ for (const auto i: types)
+ std::cout << std::to_string(i.first) << "\t" << i.second << std::endl;
+ }
+ void add(const char *type, size_t size) { types.insert(std::make_pair(size, type)); }
+private:
+ std::multimap<size_t, const std::string> types;
+};
+#define SL(type) sl.add(#type, sizeof(type))
+
+int main(int argc, char* argv[])
+{
+ size_logger sl;
+
+ tools::sanitize_locale();
+
+ mlog_configure("", true);
+
+ SL(boost::thread);
+ SL(boost::asio::io_service);
+ SL(boost::asio::io_service::work);
+ SL(boost::asio::deadline_timer);
+
+ SL(cryptonote::DB_ERROR);
+ SL(cryptonote::mdb_txn_safe);
+ SL(cryptonote::mdb_threadinfo);
+
+ SL(cryptonote::block_header);
+ SL(cryptonote::block);
+ SL(cryptonote::transaction_prefix);
+ SL(cryptonote::transaction);
+
+ SL(cryptonote::txpool_tx_meta_t);
+
+ SL(epee::net_utils::network_address_base);
+ SL(epee::net_utils::ipv4_network_address);
+ SL(epee::net_utils::network_address);
+ SL(epee::net_utils::connection_context_base);
+ SL(epee::net_utils::connection_basic);
+
+ SL(nodetool::peerlist_entry);
+ SL(nodetool::anchor_peerlist_entry);
+ SL(nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core>>);
+ SL(nodetool::p2p_connection_context_t<cryptonote::t_cryptonote_protocol_handler<cryptonote::core>::connection_context>);
+ SL(nodetool::network_address_old);
+
+ SL(tools::wallet2::transfer_details);
+ SL(tools::wallet2::payment_details);
+ SL(tools::wallet2::unconfirmed_transfer_details);
+ SL(tools::wallet2::confirmed_transfer_details);
+ SL(tools::wallet2::tx_construction_data);
+ SL(tools::wallet2::pending_tx);
+ SL(tools::wallet2::unsigned_tx_set);
+ SL(tools::wallet2::signed_tx_set);
+
+ SL(Monero::WalletImpl);
+ SL(Monero::AddressBookRow);
+ SL(Monero::TransactionInfoImpl);
+ SL(Monero::TransactionHistoryImpl);
+ SL(Monero::PendingTransactionImpl);
+ SL(Monero::UnsignedTransactionImpl);
+
+ return 0;
+}
diff --git a/src/mnemonics/CMakeLists.txt b/src/mnemonics/CMakeLists.txt
index 269cfe846..942b6eca3 100644
--- a/src/mnemonics/CMakeLists.txt
+++ b/src/mnemonics/CMakeLists.txt
@@ -45,7 +45,8 @@ set(mnemonics_private_headers
portuguese.h
russian.h
singleton.h
- spanish.h)
+ spanish.h
+ esperanto.h)
monero_private_headers(mnemonics
${mnemonics_private_headers})
diff --git a/src/mnemonics/electrum-words.cpp b/src/mnemonics/electrum-words.cpp
index 3b1dc53d7..2fe5d9985 100644
--- a/src/mnemonics/electrum-words.cpp
+++ b/src/mnemonics/electrum-words.cpp
@@ -61,6 +61,7 @@
#include "portuguese.h"
#include "japanese.h"
#include "russian.h"
+#include "esperanto.h"
#include "english_old.h"
#include "language_base.h"
#include "singleton.h"
@@ -95,6 +96,7 @@ namespace
Language::Singleton<Language::Portuguese>::instance(),
Language::Singleton<Language::Japanese>::instance(),
Language::Singleton<Language::Russian>::instance(),
+ Language::Singleton<Language::Esperanto>::instance(),
Language::Singleton<Language::EnglishOld>::instance()
});
Language::Base *fallback = NULL;
@@ -354,6 +356,10 @@ namespace crypto
{
language = Language::Singleton<Language::Chinese_Simplified>::instance();
}
+ else if (language_name == "Esperanto")
+ {
+ language = Language::Singleton<Language::Esperanto>::instance();
+ }
else
{
return false;
@@ -408,7 +414,8 @@ namespace crypto
Language::Singleton<Language::Portuguese>::instance(),
Language::Singleton<Language::Russian>::instance(),
Language::Singleton<Language::Japanese>::instance(),
- Language::Singleton<Language::Chinese_Simplified>::instance()
+ Language::Singleton<Language::Chinese_Simplified>::instance(),
+ Language::Singleton<Language::Esperanto>::instance()
});
for (std::vector<Language::Base*>::iterator it = language_instances.begin();
it != language_instances.end(); it++)
diff --git a/src/mnemonics/esperanto.h b/src/mnemonics/esperanto.h
new file mode 100644
index 000000000..8589f871e
--- /dev/null
+++ b/src/mnemonics/esperanto.h
@@ -0,0 +1,1695 @@
+// Copyright (c) 2014-2017, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/*!
+ * \file esperanto.h
+ *
+ * \brief New Esperanto word list and map.
+ */
+
+/*
+ * Word list authored by: dnaleor, Engelberg, ProkhorZ
+ * Sources:
+ * Baza Radikaro Oficiala
+ * Reta Vortaro (http://www.reta-vortaro.de/revo/)
+ * Esperanto Panorama - Esperanto-English Dictionary (http://www.esperanto-panorama.net/vortaro/eoen.htm)
+ * ESPDIC - Paul Denisowski (http://www.denisowski.org/Esperanto/ESPDIC/espdic.txt)
+ */
+
+#ifndef ESPERANTO_H
+#define ESPERANTO_H
+
+#include <vector>
+#include <unordered_map>
+#include "language_base.h"
+#include <string>
+
+/*!
+ * \namespace Language
+ * \brief Mnemonic language related namespace.
+ */
+namespace Language
+{
+ class Esperanto: public Base
+ {
+ public:
+ Esperanto(): Base("Esperanto", std::vector<std::string>({
+ "abako",
+ "abdiki",
+ "abelo",
+ "abituriento",
+ "ablativo",
+ "abnorma",
+ "abonantoj",
+ "abrikoto",
+ "absoluta",
+ "abunda",
+ "acetono",
+ "acida",
+ "adapti",
+ "adekvata",
+ "adheri",
+ "adicii",
+ "adjektivo",
+ "administri",
+ "adolesko",
+ "adreso",
+ "adstringa",
+ "adulto",
+ "advokato",
+ "adzo",
+ "aeroplano",
+ "aferulo",
+ "afgana",
+ "afiksi",
+ "aflaba",
+ "aforismo",
+ "afranki",
+ "aftozo",
+ "afusto",
+ "agavo",
+ "agento",
+ "agiti",
+ "aglo",
+ "agmaniero",
+ "agnoski",
+ "agordo",
+ "agrabla",
+ "agtipo",
+ "agutio",
+ "aikido",
+ "ailanto",
+ "aina",
+ "ajatolo",
+ "ajgenvaloro",
+ "ajlobulbo",
+ "ajnlitera",
+ "ajuto",
+ "ajzi",
+ "akademio",
+ "akcepti",
+ "akeo",
+ "akiri",
+ "aklamado",
+ "akmeo",
+ "akno",
+ "akompani",
+ "akrobato",
+ "akselo",
+ "aktiva",
+ "akurata",
+ "akvofalo",
+ "alarmo",
+ "albumo",
+ "alcedo",
+ "aldoni",
+ "aleo",
+ "alfabeto",
+ "algo",
+ "alhasti",
+ "aligatoro",
+ "alkoholo",
+ "almozo",
+ "alnomo",
+ "alojo",
+ "alpinisto",
+ "alrigardi",
+ "alskribi",
+ "alta",
+ "alumeto",
+ "alveni",
+ "alzaca",
+ "amaso",
+ "ambasado",
+ "amdeklaro",
+ "amebo",
+ "amfibio",
+ "amhara",
+ "amiko",
+ "amkanto",
+ "amletero",
+ "amnestio",
+ "amoranto",
+ "amplekso",
+ "amrakonto",
+ "amsterdama",
+ "amuzi",
+ "ananaso",
+ "androido",
+ "anekdoto",
+ "anfrakto",
+ "angulo",
+ "anheli",
+ "animo",
+ "anjono",
+ "ankro",
+ "anonci",
+ "anpriskribo",
+ "ansero",
+ "antikva",
+ "anuitato",
+ "aorto",
+ "aparta",
+ "aperti",
+ "apika",
+ "aplikado",
+ "apneo",
+ "apogi",
+ "aprobi",
+ "apsido",
+ "apterigo",
+ "apudesto",
+ "araneo",
+ "arbo",
+ "ardeco",
+ "aresti",
+ "argilo",
+ "aristokrato",
+ "arko",
+ "arlekeno",
+ "armi",
+ "arniko",
+ "aromo",
+ "arpio",
+ "arsenalo",
+ "artisto",
+ "aruba",
+ "arvorto",
+ "asaio",
+ "asbesto",
+ "ascendi",
+ "asekuri",
+ "asfalto",
+ "asisti",
+ "askalono",
+ "asocio",
+ "aspekti",
+ "astro",
+ "asulo",
+ "atakonto",
+ "atendi",
+ "atingi",
+ "atleto",
+ "atmosfero",
+ "atomo",
+ "atropino",
+ "atuto",
+ "avataro",
+ "aventuro",
+ "aviadilo",
+ "avokado",
+ "azaleo",
+ "azbuko",
+ "azenino",
+ "azilpetanto",
+ "azoto",
+ "azteka",
+ "babili",
+ "bacilo",
+ "badmintono",
+ "bagatelo",
+ "bahama",
+ "bajoneto",
+ "baki",
+ "balai",
+ "bambuo",
+ "bani",
+ "baobabo",
+ "bapti",
+ "baro",
+ "bastono",
+ "batilo",
+ "bavara",
+ "bazalto",
+ "beata",
+ "bebofono",
+ "bedo",
+ "begonio",
+ "behaviorismo",
+ "bejlo",
+ "bekero",
+ "belarto",
+ "bemolo",
+ "benko",
+ "bereto",
+ "besto",
+ "betulo",
+ "bevelo",
+ "bezoni",
+ "biaso",
+ "biblioteko",
+ "biciklo",
+ "bidaro",
+ "bieno",
+ "bifsteko",
+ "bigamiulo",
+ "bijekcio",
+ "bikino",
+ "bildo",
+ "bimetalismo",
+ "bindi",
+ "biografio",
+ "birdo",
+ "biskvito",
+ "bitlibro",
+ "bivako",
+ "bizara",
+ "bjalistoka",
+ "blanka",
+ "bleki",
+ "blinda",
+ "blovi",
+ "blua",
+ "boato",
+ "bobsledo",
+ "bocvanano",
+ "bodisatvo",
+ "bofratino",
+ "bogefratoj",
+ "bohema",
+ "boji",
+ "bokalo",
+ "boli",
+ "bombono",
+ "bona",
+ "bopatrino",
+ "bordo",
+ "bosko",
+ "botelo",
+ "bovido",
+ "brakpleno",
+ "bretaro",
+ "brikmuro",
+ "broso",
+ "brulema",
+ "bubalo",
+ "buctrapi",
+ "budo",
+ "bufedo",
+ "bugio",
+ "bujabeso",
+ "buklo",
+ "buldozo",
+ "bumerango",
+ "bunta",
+ "burokrataro",
+ "busbileto",
+ "butero",
+ "buzuko",
+ "caro",
+ "cebo",
+ "ceceo",
+ "cedro",
+ "cefalo",
+ "cejana",
+ "cekumo",
+ "celebri",
+ "cemento",
+ "cent",
+ "cepo",
+ "certa",
+ "cetera",
+ "cezio",
+ "ciano",
+ "cibeto",
+ "cico",
+ "cidro",
+ "cifero",
+ "cigaredo",
+ "ciklo",
+ "cilindro",
+ "cimbalo",
+ "cinamo",
+ "cipreso",
+ "cirkonstanco",
+ "cisterno",
+ "citrono",
+ "ciumi",
+ "civilizado",
+ "colo",
+ "congo",
+ "cunamo",
+ "cvana",
+ "dabi",
+ "daco",
+ "dadaismo",
+ "dafodilo",
+ "dago",
+ "daimio",
+ "dajmono",
+ "daktilo",
+ "dalio",
+ "damo",
+ "danki",
+ "darmo",
+ "datumoj",
+ "dazipo",
+ "deadmoni",
+ "debeto",
+ "decidi",
+ "dedukti",
+ "deerigi",
+ "defendi",
+ "degeli",
+ "dehaki",
+ "deirpunkto",
+ "deklaracio",
+ "delikata",
+ "demandi",
+ "dento",
+ "dependi",
+ "derivi",
+ "desegni",
+ "detrui",
+ "devi",
+ "deziri",
+ "dialogo",
+ "dicentro",
+ "didaktika",
+ "dieto",
+ "diferenci",
+ "digesti",
+ "diino",
+ "dikfingro",
+ "diligenta",
+ "dimensio",
+ "dinamo",
+ "diodo",
+ "diplomo",
+ "direkte",
+ "diskuti",
+ "diurno",
+ "diversa",
+ "dizajno",
+ "dobrogitaro",
+ "docento",
+ "dogano",
+ "dojeno",
+ "doktoro",
+ "dolori",
+ "domego",
+ "donaci",
+ "dopado",
+ "dormi",
+ "dosierujo",
+ "dotita",
+ "dozeno",
+ "drato",
+ "dresi",
+ "drinki",
+ "droni",
+ "druido",
+ "duaranga",
+ "dubi",
+ "ducent",
+ "dudek",
+ "duelo",
+ "dufoje",
+ "dugongo",
+ "duhufa",
+ "duilo",
+ "dujare",
+ "dukato",
+ "duloka",
+ "dumtempe",
+ "dungi",
+ "duobla",
+ "dupiedulo",
+ "dura",
+ "dusenca",
+ "dutaga",
+ "duuma",
+ "duvalvuloj",
+ "duzo",
+ "ebena",
+ "eblecoj",
+ "ebono",
+ "ebria",
+ "eburo",
+ "ecaro",
+ "ecigi",
+ "ecoj",
+ "edelvejso",
+ "editoro",
+ "edro",
+ "eduki",
+ "edzino",
+ "efektiva",
+ "efiki",
+ "efloreski",
+ "egala",
+ "egeco",
+ "egiptologo",
+ "eglefino",
+ "egoista",
+ "egreto",
+ "ejakuli",
+ "ejlo",
+ "ekarto",
+ "ekbruligi",
+ "ekceli",
+ "ekde",
+ "ekesti",
+ "ekfirmao",
+ "ekgliti",
+ "ekhavi",
+ "ekipi",
+ "ekkapti",
+ "eklezio",
+ "ekmalsati",
+ "ekonomio",
+ "ekpluvi",
+ "ekrano",
+ "ekster",
+ "ektiri",
+ "ekumeno",
+ "ekvilibro",
+ "ekzemplo",
+ "elasta",
+ "elbalai",
+ "elcento",
+ "eldoni",
+ "elektro",
+ "elfari",
+ "elgliti",
+ "elhaki",
+ "elipso",
+ "elkovi",
+ "ellasi",
+ "elmeti",
+ "elnutri",
+ "elokventa",
+ "elparoli",
+ "elrevigi",
+ "elstari",
+ "elteni",
+ "eluzita",
+ "elvoki",
+ "elzasa",
+ "emajlo",
+ "embaraso",
+ "emerito",
+ "emfazo",
+ "eminenta",
+ "emocio",
+ "empiria",
+ "emulsio",
+ "enarkivigi",
+ "enboteligi",
+ "enciklopedio",
+ "endorfino",
+ "energio",
+ "enfermi",
+ "engluti",
+ "enhavo",
+ "enigmo",
+ "enjekcio",
+ "enketi",
+ "enlanda",
+ "enmeti",
+ "enorma",
+ "enplanti",
+ "enradiki",
+ "enspezo",
+ "entrepreni",
+ "enui",
+ "envolvi",
+ "enzimo",
+ "eono",
+ "eosto",
+ "epitafo",
+ "epoko",
+ "epriskribebla",
+ "epsilono",
+ "erari",
+ "erbio",
+ "erco",
+ "erekti",
+ "ergonomia",
+ "erikejo",
+ "ermito",
+ "erotika",
+ "erpilo",
+ "erupcio",
+ "esameno",
+ "escepti",
+ "esenco",
+ "eskapi",
+ "esotera",
+ "esperi",
+ "estonto",
+ "etapo",
+ "etendi",
+ "etfingro",
+ "etikedo",
+ "etlitero",
+ "etmakleristo",
+ "etnika",
+ "etoso",
+ "etradio",
+ "etskala",
+ "etullernejo",
+ "evakui",
+ "evento",
+ "eviti",
+ "evolui",
+ "ezoko",
+ "fabriko",
+ "facila",
+ "fadeno",
+ "fagoto",
+ "fajro",
+ "fakto",
+ "fali",
+ "familio",
+ "fanatiko",
+ "farbo",
+ "fasko",
+ "fatala",
+ "favora",
+ "fazeolo",
+ "febro",
+ "federacio",
+ "feino",
+ "fekunda",
+ "felo",
+ "femuro",
+ "fenestro",
+ "fermi",
+ "festi",
+ "fetora",
+ "fezo",
+ "fiasko",
+ "fibro",
+ "fidela",
+ "fiera",
+ "fifama",
+ "figuro",
+ "fiherbo",
+ "fiinsekto",
+ "fiksa",
+ "filmo",
+ "fimensa",
+ "finalo",
+ "fiolo",
+ "fiparoli",
+ "firmao",
+ "fisko",
+ "fitingo",
+ "fiuzanto",
+ "fivorto",
+ "fiziko",
+ "fjordo",
+ "flago",
+ "flegi",
+ "flirti",
+ "floro",
+ "flugi",
+ "fobio",
+ "foceno",
+ "foirejo",
+ "fojfoje",
+ "fokuso",
+ "folio",
+ "fomenti",
+ "fonto",
+ "formulo",
+ "fosforo",
+ "fotografi",
+ "fratino",
+ "fremda",
+ "friti",
+ "frosto",
+ "frua",
+ "ftizo",
+ "fuelo",
+ "fugo",
+ "fuksia",
+ "fulmilo",
+ "fumanto",
+ "fundamento",
+ "fuorto",
+ "furioza",
+ "fusilo",
+ "futbalo",
+ "fuzio",
+ "gabardino",
+ "gado",
+ "gaela",
+ "gafo",
+ "gagato",
+ "gaja",
+ "gaki",
+ "galanta",
+ "gamao",
+ "ganto",
+ "gapulo",
+ "gardi",
+ "gasto",
+ "gavio",
+ "gazeto",
+ "geamantoj",
+ "gebani",
+ "geedzeco",
+ "gefratoj",
+ "geheno",
+ "gejsero",
+ "geko",
+ "gelateno",
+ "gemisto",
+ "geniulo",
+ "geografio",
+ "gepardo",
+ "geranio",
+ "gestolingvo",
+ "geto",
+ "geumo",
+ "gibono",
+ "giganta",
+ "gildo",
+ "gimnastiko",
+ "ginekologo",
+ "gipsi",
+ "girlando",
+ "gistfungo",
+ "gitaro",
+ "glazuro",
+ "glebo",
+ "gliti",
+ "globo",
+ "gluti",
+ "gnafalio",
+ "gnejso",
+ "gnomo",
+ "gnuo",
+ "gobio",
+ "godetio",
+ "goeleto",
+ "gojo",
+ "golfludejo",
+ "gombo",
+ "gondolo",
+ "gorilo",
+ "gospelo",
+ "gotika",
+ "granda",
+ "greno",
+ "griza",
+ "groto",
+ "grupo",
+ "guano",
+ "gubernatoro",
+ "gudrotuko",
+ "gufo",
+ "gujavo",
+ "guldeno",
+ "gumi",
+ "gupio",
+ "guruo",
+ "gusto",
+ "guto",
+ "guvernistino",
+ "gvardio",
+ "gverilo",
+ "gvidanto",
+ "habitato",
+ "hadito",
+ "hafnio",
+ "hagiografio",
+ "haitiano",
+ "hajlo",
+ "hakbloko",
+ "halti",
+ "hamstro",
+ "hangaro",
+ "hapalo",
+ "haro",
+ "hasta",
+ "hati",
+ "havebla",
+ "hazardo",
+ "hebrea",
+ "hedero",
+ "hegemonio",
+ "hejmo",
+ "hektaro",
+ "helpi",
+ "hemisfero",
+ "heni",
+ "hepato",
+ "herbo",
+ "hesa",
+ "heterogena",
+ "heziti",
+ "hiacinto",
+ "hibrida",
+ "hidrogeno",
+ "hieroglifo",
+ "higieno",
+ "hihii",
+ "hilumo",
+ "himno",
+ "hindino",
+ "hiperteksto",
+ "hirundo",
+ "historio",
+ "hobio",
+ "hojli",
+ "hokeo",
+ "hologramo",
+ "homido",
+ "honesta",
+ "hopi",
+ "horizonto",
+ "hospitalo",
+ "hotelo",
+ "huadi",
+ "hubo",
+ "hufumo",
+ "hugenoto",
+ "hukero",
+ "huligano",
+ "humana",
+ "hundo",
+ "huoj",
+ "hupilo",
+ "hurai",
+ "husaro",
+ "hutuo",
+ "huzo",
+ "iafoje",
+ "iagrade",
+ "iamaniere",
+ "iarelate",
+ "iaspeca",
+ "ibekso",
+ "ibiso",
+ "idaro",
+ "ideala",
+ "idiomo",
+ "idolo",
+ "iele",
+ "igluo",
+ "ignori",
+ "iguamo",
+ "igvano",
+ "ikono",
+ "iksodo",
+ "ikto",
+ "iliaflanke",
+ "ilkomputilo",
+ "ilobreto",
+ "ilremedo",
+ "ilumini",
+ "imagi",
+ "imitado",
+ "imperio",
+ "imuna",
+ "incidento",
+ "industrio",
+ "inerta",
+ "infano",
+ "ingenra",
+ "inhali",
+ "iniciati",
+ "injekti",
+ "inklino",
+ "inokuli",
+ "insekto",
+ "inteligenta",
+ "inundi",
+ "inviti",
+ "ioma",
+ "ionosfero",
+ "iperito",
+ "ipomeo",
+ "irana",
+ "irejo",
+ "irigacio",
+ "ironio",
+ "isato",
+ "islamo",
+ "istempo",
+ "itinero",
+ "itrio",
+ "iuloke",
+ "iumaniere",
+ "iutempe",
+ "izolita",
+ "jado",
+ "jaguaro",
+ "jakto",
+ "jama",
+ "januaro",
+ "japano",
+ "jarringo",
+ "jazo",
+ "jenoj",
+ "jesulo",
+ "jetavio",
+ "jezuito",
+ "jodli",
+ "joviala",
+ "juano",
+ "jubileo",
+ "judismo",
+ "jufto",
+ "juki",
+ "julio",
+ "juneca",
+ "jupo",
+ "juristo",
+ "juste",
+ "juvelo",
+ "kabineto",
+ "kadrato",
+ "kafo",
+ "kahelo",
+ "kajako",
+ "kakao",
+ "kalkuli",
+ "kampo",
+ "kanti",
+ "kapitalo",
+ "karaktero",
+ "kaserolo",
+ "katapulto",
+ "kaverna",
+ "kazino",
+ "kebabo",
+ "kefiro",
+ "keglo",
+ "kejlo",
+ "kekso",
+ "kelka",
+ "kemio",
+ "kerno",
+ "kesto",
+ "kiamaniere",
+ "kibuco",
+ "kidnapi",
+ "kielo",
+ "kikero",
+ "kilogramo",
+ "kimono",
+ "kinejo",
+ "kiosko",
+ "kirurgo",
+ "kisi",
+ "kitelo",
+ "kivio",
+ "klavaro",
+ "klerulo",
+ "klini",
+ "klopodi",
+ "klubo",
+ "knabo",
+ "knedi",
+ "koalo",
+ "kobalto",
+ "kodigi",
+ "kofro",
+ "kohera",
+ "koincidi",
+ "kojoto",
+ "kokoso",
+ "koloro",
+ "komenci",
+ "kontrakto",
+ "kopio",
+ "korekte",
+ "kosti",
+ "kotono",
+ "kovri",
+ "krajono",
+ "kredi",
+ "krii",
+ "krom",
+ "kruco",
+ "ksantino",
+ "ksenono",
+ "ksilofono",
+ "ksosa",
+ "kubuto",
+ "kudri",
+ "kuglo",
+ "kuiri",
+ "kuko",
+ "kulero",
+ "kumuluso",
+ "kuneco",
+ "kupro",
+ "kuri",
+ "kuseno",
+ "kutimo",
+ "kuvo",
+ "kuzino",
+ "kvalito",
+ "kverko",
+ "kvin",
+ "kvoto",
+ "labori",
+ "laculo",
+ "ladbotelo",
+ "lafo",
+ "laguno",
+ "laikino",
+ "laktobovino",
+ "lampolumo",
+ "landkarto",
+ "laosa",
+ "lapono",
+ "larmoguto",
+ "lastjare",
+ "latitudo",
+ "lavejo",
+ "lazanjo",
+ "leciono",
+ "ledosako",
+ "leganto",
+ "lekcio",
+ "lemura",
+ "lentuga",
+ "leopardo",
+ "leporo",
+ "lerni",
+ "lesivo",
+ "letero",
+ "levilo",
+ "lezi",
+ "liano",
+ "libera",
+ "liceo",
+ "lieno",
+ "lifto",
+ "ligilo",
+ "likvoro",
+ "lila",
+ "limono",
+ "lingvo",
+ "lipo",
+ "lirika",
+ "listo",
+ "literatura",
+ "liveri",
+ "lobio",
+ "logika",
+ "lojala",
+ "lokalo",
+ "longa",
+ "lordo",
+ "lotado",
+ "loza",
+ "luanto",
+ "lubriki",
+ "lucida",
+ "ludema",
+ "luigi",
+ "lukso",
+ "luli",
+ "lumbilda",
+ "lunde",
+ "lupago",
+ "lustro",
+ "lutilo",
+ "luzerno",
+ "maato",
+ "maceri",
+ "madono",
+ "mafiano",
+ "magazeno",
+ "mahometano",
+ "maizo",
+ "majstro",
+ "maketo",
+ "malgranda",
+ "mamo",
+ "mandareno",
+ "maorio",
+ "mapigi",
+ "marini",
+ "masko",
+ "mateno",
+ "mazuto",
+ "meandro",
+ "meblo",
+ "mecenato",
+ "medialo",
+ "mefito",
+ "megafono",
+ "mejlo",
+ "mekanika",
+ "melodia",
+ "membro",
+ "mendi",
+ "mergi",
+ "mespilo",
+ "metoda",
+ "mevo",
+ "mezuri",
+ "miaflanke",
+ "micelio",
+ "mielo",
+ "migdalo",
+ "mikrofilmo",
+ "militi",
+ "mimiko",
+ "mineralo",
+ "miopa",
+ "miri",
+ "mistera",
+ "mitralo",
+ "mizeri",
+ "mjelo",
+ "mnemoniko",
+ "mobilizi",
+ "mocio",
+ "moderna",
+ "mohajro",
+ "mokadi",
+ "molaro",
+ "momento",
+ "monero",
+ "mopso",
+ "mordi",
+ "moskito",
+ "motoro",
+ "movimento",
+ "mozaiko",
+ "mueli",
+ "mukozo",
+ "muldi",
+ "mumio",
+ "munti",
+ "muro",
+ "muskolo",
+ "mutacio",
+ "muzikisto",
+ "nabo",
+ "nacio",
+ "nadlo",
+ "nafto",
+ "naiva",
+ "najbaro",
+ "nanometro",
+ "napo",
+ "narciso",
+ "naski",
+ "naturo",
+ "navigi",
+ "naztruo",
+ "neatendite",
+ "nebulo",
+ "necesa",
+ "nedankinde",
+ "neebla",
+ "nefari",
+ "negoco",
+ "nehavi",
+ "neimagebla",
+ "nektaro",
+ "nelonga",
+ "nematura",
+ "nenia",
+ "neordinara",
+ "nepra",
+ "nervuro",
+ "nesto",
+ "nete",
+ "neulo",
+ "nevino",
+ "nifo",
+ "nigra",
+ "nihilisto",
+ "nikotino",
+ "nilono",
+ "nimfeo",
+ "nitrogeno",
+ "nivelo",
+ "nobla",
+ "nocio",
+ "nodozo",
+ "nokto",
+ "nomkarto",
+ "norda",
+ "nostalgio",
+ "notbloko",
+ "novico",
+ "nuanco",
+ "nuboza",
+ "nuda",
+ "nugato",
+ "nuklea",
+ "nuligi",
+ "numero",
+ "nuntempe",
+ "nupto",
+ "nura",
+ "nutri",
+ "oazo",
+ "obei",
+ "objekto",
+ "oblikva",
+ "obolo",
+ "observi",
+ "obtuza",
+ "obuso",
+ "oceano",
+ "odekolono",
+ "odori",
+ "oferti",
+ "oficiala",
+ "ofsajdo",
+ "ofte",
+ "ogivo",
+ "ogro",
+ "ojstredoj",
+ "okaze",
+ "okcidenta",
+ "okro",
+ "oksido",
+ "oktobro",
+ "okulo",
+ "oldulo",
+ "oleo",
+ "olivo",
+ "omaro",
+ "ombro",
+ "omego",
+ "omikrono",
+ "omleto",
+ "omnibuso",
+ "onagro",
+ "ondo",
+ "oneco",
+ "onidire",
+ "onklino",
+ "onlajna",
+ "onomatopeo",
+ "ontologio",
+ "opaka",
+ "operacii",
+ "opinii",
+ "oportuna",
+ "opresi",
+ "optimisto",
+ "oratoro",
+ "orbito",
+ "ordinara",
+ "orelo",
+ "orfino",
+ "organizi",
+ "orienta",
+ "orkestro",
+ "orlo",
+ "orminejo",
+ "ornami",
+ "ortangulo",
+ "orumi",
+ "oscedi",
+ "osmozo",
+ "ostocerbo",
+ "ovalo",
+ "ovingo",
+ "ovoblanko",
+ "ovri",
+ "ovulado",
+ "ozono",
+ "pacama",
+ "padeli",
+ "pafilo",
+ "pagigi",
+ "pajlo",
+ "paketo",
+ "palaco",
+ "pampelmo",
+ "pantalono",
+ "papero",
+ "paroli",
+ "pasejo",
+ "patro",
+ "pavimo",
+ "peco",
+ "pedalo",
+ "peklita",
+ "pelikano",
+ "pensiono",
+ "peplomo",
+ "pesilo",
+ "petanto",
+ "pezoforto",
+ "piano",
+ "picejo",
+ "piede",
+ "pigmento",
+ "pikema",
+ "pilkoludo",
+ "pimento",
+ "pinglo",
+ "pioniro",
+ "pipromento",
+ "pirato",
+ "pistolo",
+ "pitoreska",
+ "piulo",
+ "pivoti",
+ "pizango",
+ "planko",
+ "plektita",
+ "plibonigi",
+ "ploradi",
+ "plurlingva",
+ "pobo",
+ "podio",
+ "poeto",
+ "pogranda",
+ "pohora",
+ "pokalo",
+ "politekniko",
+ "pomarbo",
+ "ponevosto",
+ "populara",
+ "porcelana",
+ "postkompreno",
+ "poteto",
+ "poviga",
+ "pozitiva",
+ "prapatroj",
+ "precize",
+ "pridemandi",
+ "probable",
+ "pruntanto",
+ "psalmo",
+ "psikologio",
+ "psoriazo",
+ "pterido",
+ "publiko",
+ "pudro",
+ "pufo",
+ "pugnobato",
+ "pulovero",
+ "pumpi",
+ "punkto",
+ "pupo",
+ "pureo",
+ "puso",
+ "putrema",
+ "puzlo",
+ "rabate",
+ "racionala",
+ "radiko",
+ "rafinado",
+ "raguo",
+ "rajto",
+ "rakonti",
+ "ralio",
+ "rampi",
+ "rando",
+ "rapida",
+ "rastruma",
+ "ratifiki",
+ "raviolo",
+ "razeno",
+ "reakcio",
+ "rebildo",
+ "recepto",
+ "redakti",
+ "reenigi",
+ "reformi",
+ "regiono",
+ "rehavi",
+ "reinspekti",
+ "rejesi",
+ "reklamo",
+ "relativa",
+ "rememori",
+ "renkonti",
+ "reorganizado",
+ "reprezenti",
+ "respondi",
+ "retumilo",
+ "reuzebla",
+ "revidi",
+ "rezulti",
+ "rialo",
+ "ribeli",
+ "ricevi",
+ "ridiga",
+ "rifuginto",
+ "rigardi",
+ "rikolti",
+ "rilati",
+ "rimarki",
+ "rinocero",
+ "ripozi",
+ "riski",
+ "ritmo",
+ "rivero",
+ "rizokampo",
+ "roboto",
+ "rododendro",
+ "rojo",
+ "rokmuziko",
+ "rolvorto",
+ "romantika",
+ "ronroni",
+ "rosino",
+ "rotondo",
+ "rovero",
+ "rozeto",
+ "rubando",
+ "rudimenta",
+ "rufa",
+ "rugbeo",
+ "ruino",
+ "ruleto",
+ "rumoro",
+ "runo",
+ "rupio",
+ "rura",
+ "rustimuna",
+ "ruzulo",
+ "sabato",
+ "sadismo",
+ "safario",
+ "sagaca",
+ "sakfluto",
+ "salti",
+ "samtage",
+ "sandalo",
+ "sapejo",
+ "sarongo",
+ "satelito",
+ "savano",
+ "sbiro",
+ "sciado",
+ "seanco",
+ "sebo",
+ "sedativo",
+ "segligno",
+ "sekretario",
+ "selektiva",
+ "semajno",
+ "senpeza",
+ "separeo",
+ "servilo",
+ "sesangulo",
+ "setli",
+ "seurigi",
+ "severa",
+ "sezono",
+ "sfagno",
+ "sfero",
+ "sfinkso",
+ "siatempe",
+ "siblado",
+ "sidejo",
+ "siesto",
+ "sifono",
+ "signalo",
+ "siklo",
+ "silenti",
+ "simpla",
+ "sinjoro",
+ "siropo",
+ "sistemo",
+ "situacio",
+ "siverto",
+ "sizifa",
+ "skatolo",
+ "skemo",
+ "skianto",
+ "sklavo",
+ "skorpio",
+ "skribisto",
+ "skulpti",
+ "skvamo",
+ "slango",
+ "sledeto",
+ "sliparo",
+ "smeraldo",
+ "smirgi",
+ "smokingo",
+ "smuto",
+ "snoba",
+ "snufegi",
+ "sobra",
+ "sociano",
+ "sodakvo",
+ "sofo",
+ "soifi",
+ "sojlo",
+ "soklo",
+ "soldato",
+ "somero",
+ "sonilo",
+ "sopiri",
+ "sorto",
+ "soulo",
+ "soveto",
+ "sparkado",
+ "speciala",
+ "spiri",
+ "splito",
+ "sporto",
+ "sprita",
+ "spuro",
+ "stabila",
+ "stelfiguro",
+ "stimulo",
+ "stomako",
+ "strato",
+ "studanto",
+ "subgrupo",
+ "suden",
+ "suferanta",
+ "sugesti",
+ "suito",
+ "sukero",
+ "sulko",
+ "sume",
+ "sunlumo",
+ "super",
+ "surskribeto",
+ "suspekti",
+ "suturo",
+ "svati",
+ "svenfali",
+ "svingi",
+ "svopo",
+ "tabako",
+ "taglumo",
+ "tajloro",
+ "taksimetro",
+ "talento",
+ "tamen",
+ "tanko",
+ "taoismo",
+ "tapioko",
+ "tarifo",
+ "tasko",
+ "tatui",
+ "taverno",
+ "teatro",
+ "tedlaboro",
+ "tegmento",
+ "tehoro",
+ "teknika",
+ "telefono",
+ "tempo",
+ "tenisejo",
+ "teorie",
+ "teraso",
+ "testudo",
+ "tetablo",
+ "teujo",
+ "tezo",
+ "tialo",
+ "tibio",
+ "tielnomata",
+ "tifono",
+ "tigro",
+ "tikli",
+ "timida",
+ "tinkturo",
+ "tiom",
+ "tiparo",
+ "tirkesto",
+ "titolo",
+ "tiutempe",
+ "tizano",
+ "tobogano",
+ "tofeo",
+ "togo",
+ "toksa",
+ "tolerema",
+ "tombolo",
+ "tondri",
+ "topografio",
+ "tordeti",
+ "tosti",
+ "totalo",
+ "traduko",
+ "tredi",
+ "triangulo",
+ "tropika",
+ "trumpeto",
+ "tualeto",
+ "tubisto",
+ "tufgrebo",
+ "tuja",
+ "tukano",
+ "tulipo",
+ "tumulto",
+ "tunelo",
+ "turisto",
+ "tusi",
+ "tutmonda",
+ "tvisto",
+ "udono",
+ "uesto",
+ "ukazo",
+ "ukelelo",
+ "ulcero",
+ "ulmo",
+ "ultimato",
+ "ululi",
+ "umbiliko",
+ "unco",
+ "ungego",
+ "uniformo",
+ "unkti",
+ "unukolora",
+ "uragano",
+ "urbano",
+ "uretro",
+ "urino",
+ "ursido",
+ "uskleco",
+ "usonigi",
+ "utero",
+ "utila",
+ "utopia",
+ "uverturo",
+ "uzadi",
+ "uzeblo",
+ "uzino",
+ "uzkutimo",
+ "uzofini",
+ "uzurpi",
+ "uzvaloro",
+ "vadejo",
+ "vafleto",
+ "vagono",
+ "vahabismo",
+ "vajco",
+ "vakcino",
+ "valoro",
+ "vampiro",
+ "vangharoj",
+ "vaporo",
+ "varma",
+ "vasta",
+ "vato",
+ "vazaro",
+ "veaspekta",
+ "vedismo",
+ "vegetalo",
+ "vehiklo",
+ "vejno",
+ "vekita",
+ "velstango",
+ "vemieno",
+ "vendi",
+ "vepro",
+ "verando",
+ "vespero",
+ "veturi",
+ "veziko",
+ "viando",
+ "vibri",
+ "vico",
+ "videbla",
+ "vifio",
+ "vigla",
+ "viktimo",
+ "vila",
+ "vimeno",
+ "vintro",
+ "violo",
+ "vippuno",
+ "virtuala",
+ "viskoza",
+ "vitro",
+ "viveca",
+ "viziti",
+ "vobli",
+ "vodko",
+ "vojeto",
+ "vokegi",
+ "volbo",
+ "vomema",
+ "vono",
+ "vortaro",
+ "vosto",
+ "voti",
+ "vrako",
+ "vringi",
+ "vualo",
+ "vulkano",
+ "vundo",
+ "vuvuzelo",
+ "zamenhofa",
+ "zapi",
+ "zebro",
+ "zefiro",
+ "zeloto",
+ "zenismo",
+ "zeolito",
+ "zepelino",
+ "zeto",
+ "zigzagi",
+ "zinko",
+ "zipo",
+ "zirkonio",
+ "zodiako",
+ "zoeto",
+ "zombio",
+ "zono",
+ "zoologio",
+ "zorgi",
+ "zukino",
+ "zumilo",
+ }), 4)
+ {
+ populate_maps();
+ }
+ };
+}
+
+#endif
diff --git a/src/p2p/connection_basic.cpp b/src/p2p/connection_basic.cpp
index d4fbc79e1..b95f36b99 100644
--- a/src/p2p/connection_basic.cpp
+++ b/src/p2p/connection_basic.cpp
@@ -244,8 +244,7 @@ void connection_basic::sleep_before_packet(size_t packet_size, int phase, int q
delay *= 0.50;
if (delay > 0) {
long int ms = (long int)(delay * 1000);
- MDEBUG("Sleeping in " << __FUNCTION__ << " for " << ms << " ms before packet_size="<<packet_size); // debug sleep
- _dbg1("sleep in sleep_before_packet");
+ MTRACE("Sleeping in " << __FUNCTION__ << " for " << ms << " ms before packet_size="<<packet_size); // debug sleep
boost::this_thread::sleep(boost::posix_time::milliseconds( ms ) );
}
} while(delay > 0);
@@ -264,13 +263,13 @@ void connection_basic::set_start_time() {
void connection_basic::do_send_handler_write(const void* ptr , size_t cb ) {
sleep_before_packet(cb,1,-1);
- MDEBUG("handler_write (direct) - before ASIO write, for packet="<<cb<<" B (after sleep)");
+ MTRACE("handler_write (direct) - before ASIO write, for packet="<<cb<<" B (after sleep)");
set_start_time();
}
void connection_basic::do_send_handler_write_from_queue( const boost::system::error_code& e, size_t cb, int q_len ) {
sleep_before_packet(cb,2,q_len);
- MDEBUG("handler_write (after write, from queue="<<q_len<<") - before ASIO write, for packet="<<cb<<" B (after sleep)");
+ MTRACE("handler_write (after write, from queue="<<q_len<<") - before ASIO write, for packet="<<cb<<" B (after sleep)");
set_start_time();
}
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index 4e1e60d27..22ae5ec26 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -226,6 +226,7 @@ namespace nodetool
bool is_addr_recently_failed(const epee::net_utils::network_address& addr);
bool is_priority_node(const epee::net_utils::network_address& na);
std::set<std::string> get_seed_nodes(bool testnet) const;
+ bool connect_to_seed();
template <class Container>
bool connect_to_peerlist(const Container& peers);
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index 58a7f3563..e179fc14f 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -159,7 +159,7 @@ namespace nodetool
}
catch (const std::exception &e)
{
- LOG_ERROR("Failed to load p2p config file, falling back to default config");
+ MWARNING("Failed to load p2p config file, falling back to default config");
m_peerlist = peerlist_manager(); // it was probably half clobbered by the failed load
make_default_config();
}
@@ -396,7 +396,7 @@ namespace nodetool
}
else
{
- MERROR("IPv6 unsupported, skip '" << host << "' -> " << endpoint.address().to_v6().to_string(ec));
+ MWARNING("IPv6 unsupported, skip '" << host << "' -> " << endpoint.address().to_v6().to_string(ec));
throw std::runtime_error("IPv6 unsupported");
}
}
@@ -756,19 +756,19 @@ namespace nodetool
if(code < 0)
{
- LOG_ERROR_CC(context, "COMMAND_HANDSHAKE invoke failed. (" << code << ", " << epee::levin::get_err_descr(code) << ")");
+ LOG_WARNING_CC(context, "COMMAND_HANDSHAKE invoke failed. (" << code << ", " << epee::levin::get_err_descr(code) << ")");
return;
}
if(rsp.node_data.network_id != m_network_id)
{
- LOG_ERROR_CC(context, "COMMAND_HANDSHAKE Failed, wrong network! (" << epee::string_tools::get_str_from_guid_a(rsp.node_data.network_id) << "), closing connection.");
+ LOG_WARNING_CC(context, "COMMAND_HANDSHAKE Failed, wrong network! (" << epee::string_tools::get_str_from_guid_a(rsp.node_data.network_id) << "), closing connection.");
return;
}
if(!handle_remote_peerlist(rsp.local_peerlist_new, rsp.node_data.local_time, context))
{
- LOG_ERROR_CC(context, "COMMAND_HANDSHAKE: failed to handle_remote_peerlist(...), closing connection.");
+ LOG_WARNING_CC(context, "COMMAND_HANDSHAKE: failed to handle_remote_peerlist(...), closing connection.");
add_host_fail(context.m_remote_address);
return;
}
@@ -777,7 +777,7 @@ namespace nodetool
{
if(!m_payload_handler.process_payload_sync_data(rsp.payload_data, context, true))
{
- LOG_ERROR_CC(context, "COMMAND_HANDSHAKE invoked, but process_payload_sync_data returned false, dropping connection.");
+ LOG_WARNING_CC(context, "COMMAND_HANDSHAKE invoked, but process_payload_sync_data returned false, dropping connection.");
hsh_result = false;
return;
}
@@ -805,7 +805,7 @@ namespace nodetool
if(!hsh_result)
{
- LOG_ERROR_CC(context_, "COMMAND_HANDSHAKE Failed");
+ LOG_WARNING_CC(context_, "COMMAND_HANDSHAKE Failed");
m_net_server.get_config_object().close(context_.m_connection_id);
}
else
@@ -831,7 +831,7 @@ namespace nodetool
context.m_in_timedsync = false;
if(code < 0)
{
- LOG_ERROR_CC(context, "COMMAND_TIMED_SYNC invoke failed. (" << code << ", " << epee::levin::get_err_descr(code) << ")");
+ LOG_WARNING_CC(context, "COMMAND_TIMED_SYNC invoke failed. (" << code << ", " << epee::levin::get_err_descr(code) << ")");
return;
}
@@ -848,7 +848,7 @@ namespace nodetool
if(!r)
{
- LOG_ERROR_CC(context_, "COMMAND_TIMED_SYNC Failed");
+ LOG_WARNING_CC(context_, "COMMAND_TIMED_SYNC Failed");
return false;
}
return true;
@@ -1126,6 +1126,8 @@ namespace nodetool
size_t random_index;
if (use_white_list) {
+ local_peers_count = m_peerlist.get_white_peers_count();
+ max_random_index = std::min<uint64_t>(local_peers_count -1, 20);
random_index = get_random_index_with_fixed_probability(max_random_index);
} else {
random_index = crypto::rand<size_t>() % m_peerlist.get_gray_peers_count();
@@ -1171,14 +1173,11 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::connections_maker()
+ bool node_server<t_payload_net_handler>::connect_to_seed()
{
- if (!connect_to_peerlist(m_exclusive_peers)) return false;
-
- if (!m_exclusive_peers.empty()) return true;
+ if (m_seed_nodes.empty())
+ return true;
- if(!m_peerlist.get_white_peers_count() && m_seed_nodes.size())
- {
size_t try_count = 0;
size_t current_index = crypto::rand<size_t>()%m_seed_nodes.size();
bool fallback_nodes_added = false;
@@ -1211,6 +1210,21 @@ namespace nodetool
if(++current_index >= m_seed_nodes.size())
current_index = 0;
}
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::connections_maker()
+ {
+ if (!connect_to_peerlist(m_exclusive_peers)) return false;
+
+ if (!m_exclusive_peers.empty()) return true;
+
+ size_t start_conn_count = get_outgoing_connections_count();
+ if(!m_peerlist.get_white_peers_count() && m_seed_nodes.size())
+ {
+ if (!connect_to_seed())
+ return false;
}
if (!connect_to_peerlist(m_priority_peers)) return false;
@@ -1242,6 +1256,13 @@ namespace nodetool
}
}
+ if (start_conn_count == get_outgoing_connections_count() && start_conn_count < m_config.m_net_config.connections_count)
+ {
+ MINFO("Failed to connect to any, trying seeds");
+ if (!connect_to_seed())
+ return false;
+ }
+
return true;
}
//-----------------------------------------------------------------------------------
@@ -1383,17 +1404,17 @@ namespace nodetool
uint64_t time_delata = local_time > tr.time ? local_time - tr.time: tr.time - local_time;
if(time_delata > 24*60*60 )
{
- LOG_ERROR("check_trust failed to check time conditions, local_time=" << local_time << ", proof_time=" << tr.time);
+ MWARNING("check_trust failed to check time conditions, local_time=" << local_time << ", proof_time=" << tr.time);
return false;
}
if(m_last_stat_request_time >= tr.time )
{
- LOG_ERROR("check_trust failed to check time conditions, last_stat_request_time=" << m_last_stat_request_time << ", proof_time=" << tr.time);
+ MWARNING("check_trust failed to check time conditions, last_stat_request_time=" << m_last_stat_request_time << ", proof_time=" << tr.time);
return false;
}
if(m_config.m_peer_id != tr.peer_id)
{
- LOG_ERROR("check_trust failed: peer_id mismatch (passed " << tr.peer_id << ", expected " << m_config.m_peer_id<< ")");
+ MWARNING("check_trust failed: peer_id mismatch (passed " << tr.peer_id << ", expected " << m_config.m_peer_id<< ")");
return false;
}
crypto::public_key pk = AUTO_VAL_INIT(pk);
@@ -1401,7 +1422,7 @@ namespace nodetool
crypto::hash h = get_proof_of_trust_hash(tr);
if(!crypto::check_signature(h, pk, tr.sign))
{
- LOG_ERROR("check_trust failed: sign check failed");
+ MWARNING("check_trust failed: sign check failed");
return false;
}
//update last request time
@@ -1562,13 +1583,13 @@ namespace nodetool
{
if(code <= 0)
{
- LOG_ERROR_CC(ping_context, "Failed to invoke COMMAND_PING to " << address.str() << "(" << code << ", " << epee::levin::get_err_descr(code) << ")");
+ LOG_WARNING_CC(ping_context, "Failed to invoke COMMAND_PING to " << address.str() << "(" << code << ", " << epee::levin::get_err_descr(code) << ")");
return;
}
if(rsp.status != PING_OK_RESPONSE_STATUS_TEXT || pr != rsp.peer_id)
{
- LOG_ERROR_CC(ping_context, "back ping invoke wrong response \"" << rsp.status << "\" from" << address.str() << ", hsh_peer_id=" << pr_ << ", rsp.peer_id=" << rsp.peer_id);
+ LOG_WARNING_CC(ping_context, "back ping invoke wrong response \"" << rsp.status << "\" from" << address.str() << ", hsh_peer_id=" << pr_ << ", rsp.peer_id=" << rsp.peer_id);
m_net_server.get_config_object().close(ping_context.m_connection_id);
return;
}
@@ -1578,7 +1599,7 @@ namespace nodetool
if(!inv_call_res)
{
- LOG_ERROR_CC(ping_context, "back ping invoke failed to " << address.str());
+ LOG_WARNING_CC(ping_context, "back ping invoke failed to " << address.str());
m_net_server.get_config_object().close(ping_context.m_connection_id);
return false;
}
@@ -1586,7 +1607,7 @@ namespace nodetool
});
if(!r)
{
- LOG_ERROR_CC(context, "Failed to call connect_async, network error.");
+ LOG_WARNING_CC(context, "Failed to call connect_async, network error.");
}
return r;
}
@@ -1605,7 +1626,7 @@ namespace nodetool
{
if(code < 0)
{
- LOG_ERROR_CC(context_, "COMMAND_REQUEST_SUPPORT_FLAGS invoke failed. (" << code << ", " << epee::levin::get_err_descr(code) << ")");
+ LOG_WARNING_CC(context_, "COMMAND_REQUEST_SUPPORT_FLAGS invoke failed. (" << code << ", " << epee::levin::get_err_descr(code) << ")");
return;
}
@@ -1622,7 +1643,7 @@ namespace nodetool
{
if(!m_payload_handler.process_payload_sync_data(arg.payload_data, context, false))
{
- LOG_ERROR_CC(context, "Failed to process_payload_sync_data(), dropping connection");
+ LOG_WARNING_CC(context, "Failed to process_payload_sync_data(), dropping connection");
drop_connection(context);
return 1;
}
@@ -1649,7 +1670,7 @@ namespace nodetool
if(!context.m_is_income)
{
- LOG_ERROR_CC(context, "COMMAND_HANDSHAKE came not from incoming connection");
+ LOG_WARNING_CC(context, "COMMAND_HANDSHAKE came not from incoming connection");
drop_connection(context);
add_host_fail(context.m_remote_address);
return 1;
@@ -1657,14 +1678,14 @@ namespace nodetool
if(context.peer_id)
{
- LOG_ERROR_CC(context, "COMMAND_HANDSHAKE came, but seems that connection already have associated peer_id (double COMMAND_HANDSHAKE?)");
+ LOG_WARNING_CC(context, "COMMAND_HANDSHAKE came, but seems that connection already have associated peer_id (double COMMAND_HANDSHAKE?)");
drop_connection(context);
return 1;
}
if(!m_payload_handler.process_payload_sync_data(arg.payload_data, context, true))
{
- LOG_ERROR_CC(context, "COMMAND_HANDSHAKE came, but process_payload_sync_data returned false, dropping connection.");
+ LOG_WARNING_CC(context, "COMMAND_HANDSHAKE came, but process_payload_sync_data returned false, dropping connection.");
drop_connection(context);
return 1;
}
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 30cfe3ab2..1811eeb3c 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -48,6 +48,7 @@
#include "common/util.h"
#include "common/dns_utils.h"
#include "common/base58.h"
+#include "common/scoped_message_writer.h"
#include "p2p/net_node.h"
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
#include "simplewallet.h"
@@ -62,14 +63,6 @@
#include "wallet/wallet_args.h"
#include <stdexcept>
-#ifdef HAVE_READLINE
- #include "readline_buffer.h"
- #define PAUSE_READLINE() \
- rdln::suspend_readline pause_readline;
-#else
- #define PAUSE_READLINE()
-#endif
-
using namespace std;
using namespace epee;
using namespace cryptonote;
@@ -148,84 +141,19 @@ namespace
return err;
}
- class message_writer
+ tools::scoped_message_writer success_msg_writer(bool color = false)
{
- public:
- message_writer(console_colors color = console_color_default, bool bright = false,
- std::string&& prefix = std::string(), el::Level log_level = el::Level::Info)
- : m_flush(true)
- , m_color(color)
- , m_bright(bright)
- , m_log_level(log_level)
- {
- m_oss << prefix;
- }
-
- message_writer(message_writer&& rhs)
- : m_flush(std::move(rhs.m_flush))
-#if defined(_MSC_VER)
- , m_oss(std::move(rhs.m_oss))
-#else
- // GCC bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316
- , m_oss(rhs.m_oss.str(), ios_base::out | ios_base::ate)
-#endif
- , m_color(std::move(rhs.m_color))
- , m_log_level(std::move(rhs.m_log_level))
- {
- rhs.m_flush = false;
- }
-
- template<typename T>
- std::ostream& operator<<(const T& val)
- {
- m_oss << val;
- return m_oss;
- }
-
- ~message_writer()
- {
- if (m_flush)
- {
- m_flush = false;
-
- MCLOG(m_log_level, "global", m_oss.str());
-
- if (console_color_default == m_color)
- {
- std::cout << m_oss.str();
- }
- else
- {
- PAUSE_READLINE();
- set_console_color(m_color, m_bright);
- std::cout << m_oss.str();
- reset_console_color();
- }
- std::cout << std::endl;
- }
- }
-
- private:
- message_writer(message_writer& rhs);
- message_writer& operator=(message_writer& rhs);
- message_writer& operator=(message_writer&& rhs);
-
- private:
- bool m_flush;
- std::stringstream m_oss;
- console_colors m_color;
- bool m_bright;
- el::Level m_log_level;
- };
+ return tools::scoped_message_writer(color ? console_color_green : console_color_default, false, std::string(), el::Level::Info);
+ }
- message_writer success_msg_writer(bool color = false)
+ tools::scoped_message_writer message_writer(epee::console_colors color = epee::console_color_default, bool bright = false)
{
- return message_writer(color ? console_color_green : console_color_default, false, std::string(), el::Level::Info);
+ return tools::scoped_message_writer(color, bright);
}
- message_writer fail_msg_writer()
+ tools::scoped_message_writer fail_msg_writer()
{
- return message_writer(console_color_red, true, sw::tr("Error: "), el::Level::Error);
+ return tools::scoped_message_writer(console_color_red, true, sw::tr("Error: "), el::Level::Error);
}
bool is_it_true(const std::string& s)
@@ -920,14 +848,19 @@ bool simple_wallet::ask_wallet_create_if_needed()
}
else if(!wallet_file_exists && !keys_file_exists) //No wallet, no keys
{
- message_writer() << tr(m_restoring ? "Confirm wallet name: " : "No wallet found with that name. Confirm creation of new wallet named: ") << wallet_path;
- confirm_creation = command_line::input_line(tr("(Y/Yes/N/No): "));
- if(std::cin.eof())
+ bool ok = true;
+ if (!m_restoring)
{
- LOG_ERROR("Unexpected std::cin.eof() - Exited simple_wallet::ask_wallet_create_if_needed()");
- return false;
+ message_writer() << tr("No wallet found with that name. Confirm creation of new wallet named: ") << wallet_path;
+ confirm_creation = command_line::input_line(tr("(Y/Yes/N/No): "));
+ if(std::cin.eof())
+ {
+ LOG_ERROR("Unexpected std::cin.eof() - Exited simple_wallet::ask_wallet_create_if_needed()");
+ return false;
+ }
+ ok = command_line::is_yes(confirm_creation);
}
- if(command_line::is_yes(confirm_creation))
+ if (ok)
{
success_msg_writer() << tr("Generating new wallet...");
m_generate_new = wallet_path;
@@ -1094,7 +1027,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
// parse spend secret key
- std::string spendkey_string = command_line::input_line("Spend key: ");
+ std::string spendkey_string = command_line::input_line("Secret spend key: ");
if (std::cin.eof())
return false;
if (spendkey_string.empty()) {
@@ -1110,7 +1043,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
crypto::secret_key spendkey = *reinterpret_cast<const crypto::secret_key*>(spendkey_data.data());
// parse view secret key
- std::string viewkey_string = command_line::input_line("View key: ");
+ std::string viewkey_string = command_line::input_line("Secret view key: ");
if (std::cin.eof())
return false;
if (viewkey_string.empty()) {
@@ -3878,6 +3811,22 @@ static std::string get_human_readable_timestamp(uint64_t ts)
return std::string(buffer);
}
//----------------------------------------------------------------------------------------------------
+static std::string get_human_readable_timespan(std::chrono::seconds seconds)
+{
+ uint64_t ts = seconds.count();
+ if (ts < 60)
+ return std::to_string(ts) + tr(" seconds");
+ if (ts < 3600)
+ return std::to_string((uint64_t)(ts / 60)) + tr(" minutes");
+ if (ts < 3600 * 24)
+ return std::to_string((uint64_t)(ts / 3600)) + tr(" hours");
+ if (ts < 3600 * 24 * 30.5)
+ return std::to_string((uint64_t)(ts / (3600 * 24))) + tr(" days");
+ if (ts < 3600 * 24 * 365.25)
+ return std::to_string((uint64_t)(ts / (3600 * 24 * 365.25))) + tr(" months");
+ return tr("a long time");
+}
+//----------------------------------------------------------------------------------------------------
bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
{
std::vector<std::string> local_args = args_;
@@ -4186,6 +4135,19 @@ void simple_wallet::wallet_idle_thread()
}
}
//----------------------------------------------------------------------------------------------------
+std::string simple_wallet::get_prompt() const
+{
+ std::string addr_start = m_wallet->get_account().get_public_address_str(m_wallet->testnet()).substr(0, 6);
+ std::string prompt = std::string("[") + tr("wallet") + " " + addr_start;
+ uint32_t version;
+ if (!m_wallet->check_connection(&version))
+ prompt += tr(" (no daemon)");
+ else if (!m_wallet->is_synced())
+ prompt += tr(" (out of sync)");
+ prompt += "]: ";
+ return prompt;
+}
+//----------------------------------------------------------------------------------------------------
bool simple_wallet::run()
{
// check and display warning, but go on anyway
@@ -4196,9 +4158,8 @@ bool simple_wallet::run()
m_auto_refresh_enabled = m_wallet->auto_refresh();
m_idle_thread = boost::thread([&]{wallet_idle_thread();});
- std::string addr_start = m_wallet->get_account().get_public_address_str(m_wallet->testnet()).substr(0, 6);
message_writer(console_color_green, false) << "Background refresh thread started";
- return m_cmd_binder.run_handling(std::string("[") + tr("wallet") + " " + addr_start + "]: ", "");
+ return m_cmd_binder.run_handling([this](){return get_prompt();}, "");
}
//----------------------------------------------------------------------------------------------------
void simple_wallet::stop()
@@ -4520,6 +4481,12 @@ bool simple_wallet::export_key_images(const std::vector<std::string> &args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::import_key_images(const std::vector<std::string> &args)
{
+ if (!m_trusted_daemon)
+ {
+ fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon");
+ return true;
+ }
+
if (args.size() != 1)
{
fail_msg_writer() << tr("usage: import_key_images <filename>");
@@ -4684,6 +4651,8 @@ bool simple_wallet::show_transfer(const std::vector<std::string> &args)
}
crypto::hash txid = *reinterpret_cast<const crypto::hash*>(txid_data.data());
+ const uint64_t last_block_height = m_wallet->get_blockchain_current_height();
+
std::list<std::pair<crypto::hash, tools::wallet2::payment_details>> payments;
m_wallet->get_payments(payments, 0);
for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) {
@@ -4698,6 +4667,23 @@ bool simple_wallet::show_transfer(const std::vector<std::string> &args)
success_msg_writer() << "Timestamp: " << get_human_readable_timestamp(pd.m_timestamp);
success_msg_writer() << "Amount: " << print_money(pd.m_amount);
success_msg_writer() << "Payment ID: " << payment_id;
+ if (pd.m_unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER)
+ {
+ uint64_t bh = std::max(pd.m_unlock_time, pd.m_block_height + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE);
+ if (bh >= last_block_height)
+ success_msg_writer() << "Locked: " << (bh - last_block_height) << " blocks to unlock";
+ else
+ success_msg_writer() << std::to_string(last_block_height - bh) << " confirmations";
+ }
+ else
+ {
+ uint64_t current_time = static_cast<uint64_t>(time(NULL));
+ uint64_t threshold = current_time + (m_wallet->use_fork_rules(2, 0) ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1);
+ if (threshold >= pd.m_unlock_time)
+ success_msg_writer() << "unlocked for " << get_human_readable_timespan(std::chrono::seconds(threshold - pd.m_unlock_time));
+ else
+ success_msg_writer() << "locked for " << get_human_readable_timespan(std::chrono::seconds(pd.m_unlock_time - threshold));
+ }
success_msg_writer() << "Note: " << m_wallet->get_tx_note(txid);
return true;
}
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index 3cfe08082..8022c9bb2 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -182,6 +182,7 @@ namespace cryptonote
bool accept_loaded_tx(const tools::wallet2::unsigned_tx_set &txs);
bool accept_loaded_tx(const tools::wallet2::signed_tx_set &txs);
bool print_ring_members(const std::vector<tools::wallet2::pending_tx>& ptx_vector, std::ostream& ostr);
+ std::string get_prompt() const;
/*!
* \brief Prints the seed with a nice message
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index a2bb44cfe..c0974f880 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -35,6 +35,7 @@
#include "transaction_history.h"
#include "address_book.h"
#include "common_defines.h"
+#include "common/util.h"
#include "mnemonics/electrum-words.h"
#include <boost/format.hpp>
@@ -1411,6 +1412,11 @@ bool WalletImpl::parse_uri(const std::string &uri, std::string &address, std::st
return m_wallet->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error);
}
+std::string WalletImpl::getDefaultDataDir() const
+{
+ return tools::get_default_data_dir();
+}
+
bool WalletImpl::rescanSpent()
{
clearStatus();
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index 07b0f063b..8190c7873 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -129,6 +129,7 @@ public:
virtual void startRefresh();
virtual void pauseRefresh();
virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector<std::string> &unknown_parameters, std::string &error);
+ virtual std::string getDefaultDataDir() const;
private:
void clearStatus() const;
diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp
index b2f947972..a23533530 100644
--- a/src/wallet/api/wallet_manager.cpp
+++ b/src/wallet/api/wallet_manager.cpp
@@ -125,6 +125,10 @@ bool WalletManagerImpl::walletExists(const std::string &path)
return false;
}
+bool WalletManagerImpl::verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool watch_only) const
+{
+ return tools::wallet2::verify_password(keys_file_name, password, watch_only);
+}
std::vector<std::string> WalletManagerImpl::findWallets(const std::string &path)
{
diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h
index 033e8108f..aa6ea439e 100644
--- a/src/wallet/api/wallet_manager.h
+++ b/src/wallet/api/wallet_manager.h
@@ -50,6 +50,7 @@ public:
const std::string &spendKeyString = "");
virtual bool closeWallet(Wallet *wallet);
bool walletExists(const std::string &path);
+ bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool watch_only) const;
std::vector<std::string> findWallets(const std::string &path);
std::string errorString() const;
void setDaemonAddress(const std::string &address);
diff --git a/src/wallet/node_rpc_proxy.cpp b/src/wallet/node_rpc_proxy.cpp
index 1143a89d7..9f30e4ac5 100644
--- a/src/wallet/node_rpc_proxy.cpp
+++ b/src/wallet/node_rpc_proxy.cpp
@@ -48,6 +48,8 @@ NodeRPCProxy::NodeRPCProxy(epee::net_utils::http::http_simple_client &http_clien
, m_dynamic_per_kb_fee_estimate_cached_height(0)
, m_dynamic_per_kb_fee_estimate_grace_blocks(0)
, m_rpc_version(0)
+ , m_target_height(0)
+ , m_target_height_time(0)
{}
void NodeRPCProxy::invalidate()
@@ -60,9 +62,11 @@ void NodeRPCProxy::invalidate()
m_dynamic_per_kb_fee_estimate_cached_height = 0;
m_dynamic_per_kb_fee_estimate_grace_blocks = 0;
m_rpc_version = 0;
+ m_target_height = 0;
+ m_target_height_time = 0;
}
-boost::optional<std::string> NodeRPCProxy::get_rpc_version(uint32_t &rpc_version)
+boost::optional<std::string> NodeRPCProxy::get_rpc_version(uint32_t &rpc_version) const
{
const time_t now = time(NULL);
if (m_rpc_version == 0)
@@ -84,7 +88,7 @@ boost::optional<std::string> NodeRPCProxy::get_rpc_version(uint32_t &rpc_version
return boost::optional<std::string>();
}
-boost::optional<std::string> NodeRPCProxy::get_height(uint64_t &height)
+boost::optional<std::string> NodeRPCProxy::get_height(uint64_t &height) const
{
const time_t now = time(NULL);
if (m_height == 0 || now >= m_height_time + 30) // re-cache every 30 seconds
@@ -110,7 +114,32 @@ void NodeRPCProxy::set_height(uint64_t h)
m_height = h;
}
-boost::optional<std::string> NodeRPCProxy::get_earliest_height(uint8_t version, uint64_t &earliest_height)
+boost::optional<std::string> NodeRPCProxy::get_target_height(uint64_t &height) const
+{
+ const time_t now = time(NULL);
+ if (m_height == 0 || now >= m_height_time + 30) // re-cache every 30 seconds
+ {
+ epee::json_rpc::request<cryptonote::COMMAND_RPC_GET_INFO::request> req_t = AUTO_VAL_INIT(req_t);
+ epee::json_rpc::response<cryptonote::COMMAND_RPC_GET_INFO::response, std::string> resp_t = AUTO_VAL_INIT(resp_t);
+
+ req_t.jsonrpc = "2.0";
+ req_t.id = epee::serialization::storage_entry(0);
+ req_t.method = "get_info";
+ m_daemon_rpc_mutex.lock();
+ bool r = net_utils::invoke_http_json("/json_rpc", req_t, resp_t, m_http_client, rpc_timeout);
+ m_daemon_rpc_mutex.unlock();
+
+ CHECK_AND_ASSERT_MES(r, std::string(), "Failed to connect to daemon");
+ CHECK_AND_ASSERT_MES(resp_t.result.status != CORE_RPC_STATUS_BUSY, resp_t.result.status, "Failed to connect to daemon");
+ CHECK_AND_ASSERT_MES(resp_t.result.status == CORE_RPC_STATUS_OK, resp_t.result.status, "Failed to get target blockchain height");
+ m_target_height = resp_t.result.target_height;
+ m_target_height_time = now;
+ }
+ height = m_target_height;
+ return boost::optional<std::string>();
+}
+
+boost::optional<std::string> NodeRPCProxy::get_earliest_height(uint8_t version, uint64_t &earliest_height) const
{
if (m_earliest_height[version] == 0)
{
@@ -134,7 +163,7 @@ boost::optional<std::string> NodeRPCProxy::get_earliest_height(uint8_t version,
return boost::optional<std::string>();
}
-boost::optional<std::string> NodeRPCProxy::get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks, uint64_t &fee)
+boost::optional<std::string> NodeRPCProxy::get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks, uint64_t &fee) const
{
uint64_t height;
diff --git a/src/wallet/node_rpc_proxy.h b/src/wallet/node_rpc_proxy.h
index 02d1d8d93..fb288189a 100644
--- a/src/wallet/node_rpc_proxy.h
+++ b/src/wallet/node_rpc_proxy.h
@@ -43,23 +43,26 @@ public:
void invalidate();
- boost::optional<std::string> get_rpc_version(uint32_t &version);
- boost::optional<std::string> get_height(uint64_t &height);
+ boost::optional<std::string> get_rpc_version(uint32_t &version) const;
+ boost::optional<std::string> get_height(uint64_t &height) const;
void set_height(uint64_t h);
- boost::optional<std::string> get_earliest_height(uint8_t version, uint64_t &earliest_height);
- boost::optional<std::string> get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks, uint64_t &fee);
+ boost::optional<std::string> get_target_height(uint64_t &height) const;
+ boost::optional<std::string> get_earliest_height(uint8_t version, uint64_t &earliest_height) const;
+ boost::optional<std::string> get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks, uint64_t &fee) const;
private:
epee::net_utils::http::http_simple_client &m_http_client;
boost::mutex &m_daemon_rpc_mutex;
- uint64_t m_height;
- time_t m_height_time;
- uint64_t m_earliest_height[256];
- uint64_t m_dynamic_per_kb_fee_estimate;
- uint64_t m_dynamic_per_kb_fee_estimate_cached_height;
- uint64_t m_dynamic_per_kb_fee_estimate_grace_blocks;
- uint32_t m_rpc_version;
+ mutable uint64_t m_height;
+ mutable time_t m_height_time;
+ mutable uint64_t m_earliest_height[256];
+ mutable uint64_t m_dynamic_per_kb_fee_estimate;
+ mutable uint64_t m_dynamic_per_kb_fee_estimate_cached_height;
+ mutable uint64_t m_dynamic_per_kb_fee_estimate_grace_blocks;
+ mutable uint32_t m_rpc_version;
+ mutable uint64_t m_target_height;
+ mutable time_t m_target_height_time;
};
}
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index e569197b8..b63e07b2d 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1097,6 +1097,7 @@ void wallet2::process_outgoing(const crypto::hash &txid, const cryptonote::trans
}
entry.first->second.m_block_height = height;
entry.first->second.m_timestamp = ts;
+ entry.first->second.m_unlock_time = tx.unlock_time;
}
//----------------------------------------------------------------------------------------------------
void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const crypto::hash& bl_id, uint64_t height, const cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::block_output_indices &o_indices)
@@ -1878,6 +1879,10 @@ bool wallet2::clear()
m_payments.clear();
m_tx_keys.clear();
m_confirmed_txs.clear();
+ m_unconfirmed_payments.clear();
+ m_scanned_pool_txs[0].clear();
+ m_scanned_pool_txs[1].clear();
+ m_address_book.clear();
m_local_bc_height = 1;
return true;
}
@@ -1958,6 +1963,9 @@ bool wallet2::store_keys(const std::string& keys_file_name, const std::string& p
value2.SetInt(m_merge_destinations ? 1 :0);
json.AddMember("merge_destinations", value2, json.GetAllocator());
+ value2.SetInt(m_testnet ? 1 :0);
+ json.AddMember("testnet", value2, json.GetAllocator());
+
// Serialize the JSON object
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
@@ -2099,6 +2107,11 @@ bool wallet2::load_keys(const std::string& keys_file_name, const std::string& pa
m_min_output_value = field_min_output_value;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, merge_destinations, int, Int, false, false);
m_merge_destinations = field_merge_destinations;
+ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, testnet, int, Int, false, m_testnet);
+ // Wallet is being opened with testnet flag, but is saved as a mainnet wallet
+ THROW_WALLET_EXCEPTION_IF(m_testnet && !field_testnet, error::wallet_internal_error, "Mainnet wallet can not be opened as testnet wallet");
+ // Wallet is being opened without testnet flag but is saved as a testnet wallet.
+ THROW_WALLET_EXCEPTION_IF(!m_testnet && field_testnet, error::wallet_internal_error, "Testnet wallet can not be opened as mainnet wallet");
}
const cryptonote::account_keys& keys = m_account.get_keys();
@@ -2113,6 +2126,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const std::string& pa
/*!
* \brief verify password for default wallet keys file.
* \param password Password to verify
+ * \return true if password is correct
*
* for verification only
* should not mutate state, unlike load_keys()
@@ -2121,7 +2135,23 @@ bool wallet2::load_keys(const std::string& keys_file_name, const std::string& pa
*/
bool wallet2::verify_password(const std::string& password) const
{
- const std::string keys_file_name = m_keys_file;
+ return verify_password(m_keys_file, password, m_watch_only);
+}
+
+/*!
+ * \brief verify password for specified wallet keys file.
+ * \param keys_file_name Keys file to verify password for
+ * \param password Password to verify
+ * \param watch_only If set = only verify view keys, otherwise also spend keys
+ * \return true if password is correct
+ *
+ * for verification only
+ * should not mutate state, unlike load_keys()
+ * can be used prior to rewriting wallet keys file, to ensure user has entered the correct password
+ *
+ */
+bool wallet2::verify_password(const std::string& keys_file_name, const std::string& password, bool watch_only)
+{
wallet2::keys_file_data keys_file_data;
std::string buf;
bool r = epee::file_io_utils::load_file_to_string(keys_file_name, buf);
@@ -2154,7 +2184,7 @@ bool wallet2::verify_password(const std::string& password) const
const cryptonote::account_keys& keys = account_data_check.get_keys();
r = r && verify_keys(keys.m_view_secret_key, keys.m_account_address.m_view_public_key);
- if(!m_watch_only)
+ if(!watch_only)
r = r && verify_keys(keys.m_spend_secret_key, keys.m_account_address.m_spend_public_key);
return r;
}
@@ -2192,9 +2222,26 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const std::stri
// try asking the daemon first
if(m_refresh_from_block_height == 0 && !recover){
std::string err;
- uint64_t height = get_daemon_blockchain_height(err);
- if (err.empty())
- m_refresh_from_block_height = height - blocks_per_month;
+ uint64_t height = 0;
+
+ // we get the max of approximated height and known height
+ // approximated height is the least of daemon target height
+ // (the max of what the other daemons are claiming is their
+ // height) and the theoretical height based on the local
+ // clock. This will be wrong only if both the local clock
+ // is bad *and* a peer daemon claims a highest height than
+ // the real chain.
+ // known height is the height the local daemon is currently
+ // synced to, it will be lower than the real chain height if
+ // the daemon is currently syncing.
+ height = get_approximate_blockchain_height();
+ uint64_t target_height = get_daemon_blockchain_target_height(err);
+ if (err.empty() && target_height < height)
+ height = target_height;
+ uint64_t local_height = get_daemon_blockchain_height(err);
+ if (err.empty() && local_height > height)
+ height = local_height;
+ m_refresh_from_block_height = height >= blocks_per_month ? height - blocks_per_month : 0;
}
if(m_refresh_from_block_height == 0 && !recover){
@@ -5685,6 +5732,15 @@ uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, ui
}
}
//----------------------------------------------------------------------------------------------------
+bool wallet2::is_synced() const
+{
+ uint64_t height;
+ boost::optional<std::string> result = m_node_rpc_proxy.get_target_height(height);
+ if (result && *result != CORE_RPC_STATUS_OK)
+ return false;
+ return get_blockchain_current_height() >= height;
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::generate_genesis(cryptonote::block& b) {
if (m_testnet)
{
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index b853c5f3c..ba9abacf5 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -129,6 +129,8 @@ namespace tools
//! Just parses variables.
static std::unique_ptr<wallet2> make_dummy(const boost::program_options::variables_map& vm);
+ static bool verify_password(const std::string& keys_file_name, const std::string& password, bool watch_only);
+
wallet2(bool testnet = false, bool restricted = false) : m_run(true), m_callback(0), m_testnet(testnet), m_always_confirm_transfers(true), m_print_ring_members(false), m_store_tx_info(true), m_default_mixin(0), m_default_priority(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0), m_confirm_missing_payment_id(true), m_ask_password(true), m_min_output_count(0), m_min_output_value(0), m_merge_destinations(false), m_is_initialized(false), m_restricted(restricted), is_old_file_format(false), m_node_rpc_proxy(m_http_client, m_daemon_rpc_mutex) {}
struct transfer_details
@@ -199,10 +201,11 @@ namespace tools
std::vector<cryptonote::tx_destination_entry> m_dests;
crypto::hash m_payment_id;
uint64_t m_timestamp;
+ uint64_t m_unlock_time;
- confirmed_transfer_details(): m_amount_in(0), m_amount_out(0), m_change((uint64_t)-1), m_block_height(0), m_payment_id(cryptonote::null_hash) {}
+ confirmed_transfer_details(): m_amount_in(0), m_amount_out(0), m_change((uint64_t)-1), m_block_height(0), m_payment_id(cryptonote::null_hash), m_timestamp(0), m_unlock_time(0) {}
confirmed_transfer_details(const unconfirmed_transfer_details &utd, uint64_t height):
- m_amount_in(utd.m_amount_in), m_amount_out(utd.m_amount_out), m_change(utd.m_change), m_block_height(height), m_dests(utd.m_dests), m_payment_id(utd.m_payment_id), m_timestamp(utd.m_timestamp) {}
+ m_amount_in(utd.m_amount_in), m_amount_out(utd.m_amount_out), m_change(utd.m_change), m_block_height(height), m_dests(utd.m_dests), m_payment_id(utd.m_payment_id), m_timestamp(utd.m_timestamp), m_unlock_time(utd.m_tx.unlock_time) {}
};
struct tx_construction_data
@@ -597,6 +600,8 @@ namespace tools
uint64_t get_blockchain_height_by_date(uint16_t year, uint8_t month, uint8_t day); // 1<=month<=12, 1<=day<=31
+ bool is_synced() const;
+
private:
/*!
* \brief Stores wallet information to wallet file.
@@ -704,7 +709,7 @@ BOOST_CLASS_VERSION(tools::wallet2, 18)
BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 7)
BOOST_CLASS_VERSION(tools::wallet2::payment_details, 1)
BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 6)
-BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 3)
+BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 4)
BOOST_CLASS_VERSION(tools::wallet2::address_book_row, 16)
BOOST_CLASS_VERSION(tools::wallet2::unsigned_tx_set, 0)
BOOST_CLASS_VERSION(tools::wallet2::signed_tx_set, 0)
@@ -879,6 +884,13 @@ namespace boost
x.m_amount_out += x.m_change;
}
}
+ if (ver < 4)
+ {
+ if (!typename Archive::is_saving())
+ x.m_unlock_time = 0;
+ return;
+ }
+ a & x.m_unlock_time;
}
template <class Archive>
diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h
index ce431ee6b..8da8c62eb 100644
--- a/src/wallet/wallet2_api.h
+++ b/src/wallet/wallet2_api.h
@@ -596,6 +596,9 @@ struct Wallet
virtual bool verifySignedMessage(const std::string &message, const std::string &addres, const std::string &signature) const = 0;
virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector<std::string> &unknown_parameters, std::string &error) = 0;
+
+ virtual std::string getDefaultDataDir() const = 0;
+
/*
* \brief rescanSpent - Rescan spent outputs - Can only be used with trusted daemon
* \return true on success
@@ -669,11 +672,20 @@ struct WalletManager
/*!
* @brief TODO: delme walletExists - check if the given filename is the wallet
* @param path - filename
- * @return
+ * @return - true if wallet exists
*/
virtual bool walletExists(const std::string &path) = 0;
/*!
+ * @brief verifyWalletPassword - check if the given filename is the wallet
+ * @param keys_file_name - location of keys file
+ * @param password - password to verify
+ * @param watch_only - verify only view keys?
+ * @return - true if password is correct
+ */
+ virtual bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool watch_only) const = 0;
+
+ /*!
* \brief findWallets - searches for the wallet files by given path name recursively
* \param path - starting point to search
* \return - list of strings with found wallets (absolute paths);
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index f014c573a..773d12775 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -227,6 +227,19 @@ namespace tools
return false;
}
//------------------------------------------------------------------------------------------------------------------------------
+ uint64_t wallet_rpc_server::adjust_mixin(uint64_t mixin)
+ {
+ if (mixin < 4 && m_wallet->use_fork_rules(6, 10)) {
+ MWARNING("Requested ring size " << (mixin + 1) << " too low for hard fork 6, using 5");
+ mixin = 4;
+ }
+ else if (mixin < 2 && m_wallet->use_fork_rules(2, 10)) {
+ MWARNING("Requested ring size " << (mixin + 1) << " too low for hard fork 2, using 3");
+ mixin = 2;
+ }
+ return mixin;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
void wallet_rpc_server::fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &txid, const crypto::hash &payment_id, const tools::wallet2::payment_details &pd)
{
entry.txid = string_tools::pod_to_hex(pd.m_tx_hash);
@@ -236,6 +249,7 @@ namespace tools
entry.height = pd.m_block_height;
entry.timestamp = pd.m_timestamp;
entry.amount = pd.m_amount;
+ entry.unlock_time = pd.m_unlock_time;
entry.fee = 0; // TODO
entry.note = m_wallet->get_tx_note(pd.m_tx_hash);
entry.type = "in";
@@ -249,6 +263,7 @@ namespace tools
entry.payment_id = entry.payment_id.substr(0,16);
entry.height = pd.m_block_height;
entry.timestamp = pd.m_timestamp;
+ entry.unlock_time = pd.m_unlock_time;
entry.fee = pd.m_amount_in - pd.m_amount_out;
uint64_t change = pd.m_change == (uint64_t)-1 ? 0 : pd.m_change; // change may not be known
entry.amount = pd.m_amount_in - change - entry.fee;
@@ -276,6 +291,7 @@ namespace tools
entry.timestamp = pd.m_timestamp;
entry.fee = pd.m_amount_in - pd.m_amount_out;
entry.amount = pd.m_amount_in - pd.m_change - entry.fee;
+ entry.unlock_time = pd.m_tx.unlock_time;
entry.note = m_wallet->get_tx_note(txid);
entry.type = is_failed ? "failed" : "pending";
}
@@ -289,6 +305,7 @@ namespace tools
entry.height = 0;
entry.timestamp = pd.m_timestamp;
entry.amount = pd.m_amount;
+ entry.unlock_time = pd.m_unlock_time;
entry.fee = 0; // TODO
entry.note = m_wallet->get_tx_note(pd.m_tx_hash);
entry.type = "pool";
@@ -454,11 +471,7 @@ namespace tools
try
{
- uint64_t mixin = req.mixin;
- if (mixin < 2 && m_wallet->use_fork_rules(2, 10)) {
- LOG_PRINT_L1("Requested ring size " << (req.mixin + 1) << " too low for hard fork 2, using 3");
- mixin = 2;
- }
+ uint64_t mixin = adjust_mixin(req.mixin);
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, req.priority, extra, m_trusted_daemon);
// reject proposed transactions if there are more than one. see on_transfer_split below.
@@ -531,12 +544,8 @@ namespace tools
try
{
- uint64_t mixin = req.mixin;
+ uint64_t mixin = adjust_mixin(req.mixin);
uint64_t ptx_amount;
- if (mixin < 2 && m_wallet->use_fork_rules(2, 10)) {
- LOG_PRINT_L1("Requested ring size " << (req.mixin + 1) << " too low for hard fork 2, using 3");
- mixin = 2;
- }
std::vector<wallet2::pending_tx> ptx_vector;
LOG_PRINT_L2("on_transfer_split calling create_transactions_2");
ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, req.priority, extra, m_trusted_daemon);
@@ -678,7 +687,8 @@ namespace tools
try
{
- std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_all(req.below_amount, dsts[0].addr, req.mixin, req.unlock_time, req.priority, extra, m_trusted_daemon);
+ uint64_t mixin = adjust_mixin(req.mixin);
+ std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_all(req.below_amount, dsts[0].addr, mixin, req.unlock_time, req.priority, extra, m_trusted_daemon);
if (!req.do_not_relay)
m_wallet->commit_tx(ptx_vector);
@@ -1360,7 +1370,12 @@ namespace tools
er.message = "Command unavailable in restricted mode.";
return false;
}
-
+ if (!m_trusted_daemon)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "This command requires a trusted daemon.";
+ return false;
+ }
try
{
std::vector<std::pair<crypto::key_image, crypto::signature>> ski;
diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h
index 68e4c049a..dd54222b0 100644
--- a/src/wallet/wallet_rpc_server.h
+++ b/src/wallet/wallet_rpc_server.h
@@ -150,6 +150,7 @@ namespace tools
void fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &txid, const tools::wallet2::unconfirmed_transfer_details &pd);
void fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &payment_id, const tools::wallet2::payment_details &pd);
bool not_open(epee::json_rpc::error& er);
+ uint64_t adjust_mixin(uint64_t mixin);
wallet2 *m_wallet;
std::string m_wallet_dir;
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index 5832bb032..fa5c154de 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -560,6 +560,7 @@ namespace wallet_rpc
std::string note;
std::list<transfer_destination> destinations;
std::string type;
+ uint64_t unlock_time;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(txid);
@@ -571,6 +572,7 @@ namespace wallet_rpc
KV_SERIALIZE(note);
KV_SERIALIZE(destinations);
KV_SERIALIZE(type);
+ KV_SERIALIZE(unlock_time)
END_KV_SERIALIZE_MAP()
};
diff --git a/tests/core_proxy/core_proxy.h b/tests/core_proxy/core_proxy.h
index 35e88081b..b7d5725f0 100644
--- a/tests/core_proxy/core_proxy.h
+++ b/tests/core_proxy/core_proxy.h
@@ -96,5 +96,7 @@ namespace tests
bool get_blocks(uint64_t start_offset, size_t count, std::list<std::pair<cryptonote::blobdata, cryptonote::block>>& blocks, std::list<cryptonote::blobdata>& txs) const { return false; }
bool get_transactions(const std::vector<crypto::hash>& txs_ids, std::list<cryptonote::transaction>& txs, std::list<crypto::hash>& missed_txs) const { return false; }
bool get_block_by_hash(const crypto::hash &h, cryptonote::block &blk, bool *orphan = NULL) const { return false; }
+ uint8_t get_ideal_hard_fork_version(uint64_t height) const { return 0; }
+ uint8_t get_hard_fork_version(uint64_t height) const { return 0; }
};
}
diff --git a/tests/unit_tests/ban.cpp b/tests/unit_tests/ban.cpp
index 694d733ec..6fc8b83dd 100644
--- a/tests/unit_tests/ban.cpp
+++ b/tests/unit_tests/ban.cpp
@@ -73,6 +73,8 @@ public:
bool get_blocks(uint64_t start_offset, size_t count, std::list<std::pair<cryptonote::blobdata, cryptonote::block>>& blocks, std::list<cryptonote::blobdata>& txs) const { return false; }
bool get_transactions(const std::vector<crypto::hash>& txs_ids, std::list<cryptonote::transaction>& txs, std::list<crypto::hash>& missed_txs) const { return false; }
bool get_block_by_hash(const crypto::hash &h, cryptonote::block &blk, bool *orphan = NULL) const { return false; }
+ uint8_t get_ideal_hard_fork_version(uint64_t height) const { return 0; }
+ uint8_t get_hard_fork_version(uint64_t height) const { return 0; }
};
typedef nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<test_core>> Server;
diff --git a/tests/unit_tests/mnemonics.cpp b/tests/unit_tests/mnemonics.cpp
index 553dcfb86..05894adf4 100644
--- a/tests/unit_tests/mnemonics.cpp
+++ b/tests/unit_tests/mnemonics.cpp
@@ -44,6 +44,7 @@
#include "mnemonics/russian.h"
#include "mnemonics/french.h"
#include "mnemonics/dutch.h"
+#include "mnemonics/esperanto.h"
#include "mnemonics/english_old.h"
#include "mnemonics/language_base.h"
#include "mnemonics/singleton.h"
@@ -165,7 +166,8 @@ TEST(mnemonics, all_languages)
Language::Singleton<Language::Italian>::instance(),
Language::Singleton<Language::Russian>::instance(),
Language::Singleton<Language::French>::instance(),
- Language::Singleton<Language::Dutch>::instance()
+ Language::Singleton<Language::Dutch>::instance(),
+ Language::Singleton<Language::Esperanto>::instance()
});
for (std::vector<Language::Base*>::iterator it = languages.begin(); it != languages.end(); it++)