aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt28
-rw-r--r--README.md2
-rw-r--r--contrib/epee/include/net/levin_protocol_handler_async.h78
-rw-r--r--contrib/epee/include/storages/http_abstract_invoke.h2
-rw-r--r--contrib/epee/src/memwipe.c6
-rw-r--r--external/db_drivers/liblmdb/mdb.c4
-rw-r--r--external/easylogging++/easylogging++.cc6
-rw-r--r--src/common/int-util.h9
-rw-r--r--src/common/rpc_client.h16
-rw-r--r--src/crypto/chacha.c2
-rw-r--r--src/crypto/crypto.cpp19
-rw-r--r--src/crypto/keccak.c17
-rw-r--r--src/crypto/oaes_lib.c14
-rw-r--r--src/crypto/random.c4
-rw-r--r--src/crypto/tree-hash.c4
-rw-r--r--src/cryptonote_basic/cryptonote_boost_serialization.h8
-rw-r--r--src/cryptonote_core/blockchain.cpp9
-rw-r--r--src/cryptonote_core/cryptonote_tx_utils.cpp22
-rw-r--r--src/cryptonote_core/cryptonote_tx_utils.h2
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.h2
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl6
-rw-r--r--src/daemon/command_parser_executor.cpp17
-rw-r--r--src/daemon/command_parser_executor.h4
-rw-r--r--src/daemon/command_server.cpp6
-rw-r--r--src/daemon/daemon.cpp2
-rw-r--r--src/daemon/main.cpp2
-rw-r--r--src/daemon/protocol.h4
-rw-r--r--src/daemon/rpc.h18
-rw-r--r--src/daemon/rpc_command_executor.cpp59
-rw-r--r--src/daemon/rpc_command_executor.h4
-rw-r--r--src/p2p/net_node.cpp1
-rw-r--r--src/p2p/net_node.h8
-rw-r--r--src/p2p/net_node.inl79
-rw-r--r--src/p2p/p2p_protocol_defs.h6
-rw-r--r--src/ringct/bulletproofs.cc103
-rw-r--r--src/ringct/rctSigs.cpp60
-rw-r--r--src/ringct/rctTypes.h18
-rw-r--r--src/rpc/core_rpc_server.cpp288
-rw-r--r--src/rpc/core_rpc_server.h16
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h88
-rw-r--r--src/rpc/rpc_args.cpp2
-rw-r--r--src/simplewallet/simplewallet.cpp22
-rw-r--r--src/wallet/api/address_book.cpp2
-rw-r--r--src/wallet/api/wallet.cpp4
-rw-r--r--src/wallet/wallet2.cpp20
-rw-r--r--src/wallet/wallet2.h6
-rw-r--r--src/wallet/wallet_rpc_server.cpp18
-rw-r--r--tests/fuzz/CMakeLists.txt2
-rw-r--r--translations/monero.ts34
-rw-r--r--translations/monero_fr.ts40
-rw-r--r--translations/monero_it.ts48
-rw-r--r--translations/monero_sv.ts4
52 files changed, 956 insertions, 289 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 730a0f875..f0be28845 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -33,6 +33,7 @@ include(CheckCCompilerFlag)
include(CheckCXXCompilerFlag)
include(CheckLinkerFlag)
include(CheckLibraryExists)
+include(CheckFunctionExists)
if (IOS)
INCLUDE(CmakeLists_IOS.txt)
@@ -80,6 +81,22 @@ function (add_linker_flag_if_supported flag var)
endif()
endfunction()
+function (add_definition_if_function_found function var)
+ string(REPLACE "-" "_" supported ${function}_function)
+ check_function_exists(${function} ${supported})
+ if(${${supported}})
+ add_definitions("-D${var}")
+ endif()
+endfunction()
+
+function (add_definition_if_library_exists library function header var)
+ string(REPLACE "-" "_" supported ${function}_library)
+ check_library_exists(${library} ${function} ${header} ${supported})
+ if(${${supported}})
+ add_definitions("-D${var}")
+ endif()
+endfunction()
+
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
message(STATUS "Setting default build type: ${CMAKE_BUILD_TYPE}")
@@ -395,6 +412,10 @@ if(STATIC AND NOT IOS)
endif()
endif()
+add_definition_if_library_exists(c memset_s "string.h" HAVE_MEMSET_S)
+add_definition_if_library_exists(c explicit_bzero "strings.h" HAVE_EXPLICIT_BZERO)
+add_definition_if_function_found(strptime HAVE_STRPTIME)
+
add_definitions(-DAUTO_INITIALIZE_EASYLOGGINGPP)
# Generate header for embedded translations
@@ -867,10 +888,3 @@ option(INSTALL_VENDORED_LIBUNBOUND "Install libunbound binary built from source
CHECK_C_COMPILER_FLAG(-std=c11 HAVE_C11)
-
-include(CheckLibraryExists)
-include(CheckFunctionExists)
-
-check_library_exists(c memset_s "string.h" HAVE_MEMSET_S)
-check_library_exists(c explicit_bzero "strings.h" HAVE_EXPLICIT_BZERO)
-check_function_exists(strptime HAVE_STRPTIME)
diff --git a/README.md b/README.md
index 00a2cac36..81db79575 100644
--- a/README.md
+++ b/README.md
@@ -251,7 +251,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (
```
git clone https://github.com/monero-project/monero.git
cd monero
- git checkout tags/v0.11.0.0
+ git checkout tags/v0.11.1.0
```
* Build:
```
diff --git a/contrib/epee/include/net/levin_protocol_handler_async.h b/contrib/epee/include/net/levin_protocol_handler_async.h
index ee64da5d8..de270bfd0 100644
--- a/contrib/epee/include/net/levin_protocol_handler_async.h
+++ b/contrib/epee/include/net/levin_protocol_handler_async.h
@@ -77,6 +77,8 @@ class async_protocol_handler_config
levin_commands_handler<t_connection_context>* m_pcommands_handler;
void (*m_pcommands_handler_destroy)(levin_commands_handler<t_connection_context>*);
+ void delete_connections (size_t count, bool incoming);
+
public:
typedef t_connection_context connection_context;
uint64_t m_max_packet_size;
@@ -101,6 +103,7 @@ public:
{}
~async_protocol_handler_config() { set_handler(NULL, NULL); }
void del_out_connections(size_t count);
+ void del_in_connections(size_t count);
};
@@ -731,41 +734,50 @@ void async_protocol_handler_config<t_connection_context>::del_connection(async_p
}
//------------------------------------------------------------------------------------------
template<class t_connection_context>
+void async_protocol_handler_config<t_connection_context>::delete_connections(size_t count, bool incoming)
+{
+ std::vector <boost::uuids::uuid> connections;
+ CRITICAL_REGION_BEGIN(m_connects_lock);
+ for (auto& c: m_connects)
+ {
+ if (c.second->m_connection_context.m_is_income == incoming)
+ connections.push_back(c.first);
+ }
+
+ // close random connections from the provided set
+ // TODO or better just keep removing random elements (performance)
+ unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
+ shuffle(connections.begin(), connections.end(), std::default_random_engine(seed));
+ while (count > 0 && connections.size() > 0)
+ {
+ try
+ {
+ auto i = connections.end() - 1;
+ async_protocol_handler<t_connection_context> *conn = m_connects.at(*i);
+ del_connection(conn);
+ close(*i);
+ connections.erase(i);
+ }
+ catch (const std::out_of_range &e)
+ {
+ MWARNING("Connection not found in m_connects, continuing");
+ }
+ --count;
+ }
+
+ CRITICAL_REGION_END();
+}
+//------------------------------------------------------------------------------------------
+template<class t_connection_context>
void async_protocol_handler_config<t_connection_context>::del_out_connections(size_t count)
{
- std::vector <boost::uuids::uuid> out_connections;
- CRITICAL_REGION_BEGIN(m_connects_lock);
- for (auto& c: m_connects)
- {
- if (!c.second->m_connection_context.m_is_income)
- out_connections.push_back(c.first);
- }
-
- if (out_connections.size() == 0)
- return;
-
- // close random out connections
- // TODO or better just keep removing random elements (performance)
- unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
- shuffle(out_connections.begin(), out_connections.end(), std::default_random_engine(seed));
- while (count > 0 && out_connections.size() > 0)
- {
- try
- {
- auto i = out_connections.end() - 1;
- async_protocol_handler<t_connection_context> *conn = m_connects.at(*i);
- del_connection(conn);
- close(*i);
- out_connections.erase(i);
- }
- catch (const std::out_of_range &e)
- {
- MWARNING("Connection not found in m_connects, continuing");
- }
- --count;
- }
-
- CRITICAL_REGION_END();
+ delete_connections(count, false);
+}
+//------------------------------------------------------------------------------------------
+template<class t_connection_context>
+void async_protocol_handler_config<t_connection_context>::del_in_connections(size_t count)
+{
+ delete_connections(count, true);
}
//------------------------------------------------------------------------------------------
template<class t_connection_context>
diff --git a/contrib/epee/include/storages/http_abstract_invoke.h b/contrib/epee/include/storages/http_abstract_invoke.h
index 6517f1253..d93084ab0 100644
--- a/contrib/epee/include/storages/http_abstract_invoke.h
+++ b/contrib/epee/include/storages/http_abstract_invoke.h
@@ -115,7 +115,7 @@ namespace epee
}
if(resp_t.error.code || resp_t.error.message.size())
{
- LOG_ERROR("RPC call of \"" << method_name << "\" returned error: " << resp_t.error.code << ", message: " << resp_t.error.message);
+ LOG_ERROR("RPC call of \"" << req_t.method << "\" returned error: " << resp_t.error.code << ", message: " << resp_t.error.message);
return false;
}
result_struct = resp_t.result;
diff --git a/contrib/epee/src/memwipe.c b/contrib/epee/src/memwipe.c
index 870c69757..9a83e67e8 100644
--- a/contrib/epee/src/memwipe.c
+++ b/contrib/epee/src/memwipe.c
@@ -31,6 +31,7 @@
#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>
#include <stdlib.h>
+#include <unistd.h>
#ifdef HAVE_EXPLICIT_BZERO
#include <strings.h>
#endif
@@ -50,7 +51,12 @@ void *memwipe(void *ptr, size_t n)
{
if (memset_s(ptr, n, 0, n))
{
+#ifdef NDEBUG
+ fprintf(stderr, "Error: memset_s failed\n");
+ _exit(1);
+#else
abort();
+#endif
}
SCARECROW // might as well...
return ptr;
diff --git a/external/db_drivers/liblmdb/mdb.c b/external/db_drivers/liblmdb/mdb.c
index 87b244ce7..bb0420453 100644
--- a/external/db_drivers/liblmdb/mdb.c
+++ b/external/db_drivers/liblmdb/mdb.c
@@ -1635,7 +1635,11 @@ mdb_assert_fail(MDB_env *env, const char *expr_txt,
if (env->me_assert_func)
env->me_assert_func(env, buf);
fprintf(stderr, "%s\n", buf);
+#ifdef NDEBUG
+ _exit();
+#else
abort();
+#endif
}
#else
# define mdb_assert0(env, expr, expr_txt) ((void) 0)
diff --git a/external/easylogging++/easylogging++.cc b/external/easylogging++/easylogging++.cc
index 57742b2e5..212a1822d 100644
--- a/external/easylogging++/easylogging++.cc
+++ b/external/easylogging++/easylogging++.cc
@@ -17,6 +17,8 @@
#define EASYLOGGING_CC
#include "easylogging++.h"
+#include <unistd.h>
+
#if defined(AUTO_INITIALIZE_EASYLOGGINGPP)
INITIALIZE_EASYLOGGINGPP
#endif
@@ -36,7 +38,11 @@ static void abort(int status, const std::string& reason) {
// Ignore msvc critical error dialog - break instead (on debug mode)
_asm int 3
#else
+#ifdef NDEBUG
+ ::_exit(1);
+#else
::abort();
+#endif
#endif // defined(ELPP_COMPILER_MSVC) && defined(_M_IX86) && defined(_DEBUG)
}
diff --git a/src/common/int-util.h b/src/common/int-util.h
index 11e39895e..3bcc085e2 100644
--- a/src/common/int-util.h
+++ b/src/common/int-util.h
@@ -34,7 +34,10 @@
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
+
+#ifndef _MSC_VER
#include <sys/param.h>
+#endif
#if defined(__ANDROID__)
#include <byteswap.h>
@@ -206,6 +209,12 @@ static inline void memcpy_swap64(void *dst, const void *src, size_t n) {
}
}
+#ifdef _MSC_VER
+# define LITTLE_ENDIAN 1234
+# define BIG_ENDIAN 4321
+# define BYTE_ORDER LITTLE_ENDIAN
+#endif
+
#if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN)
static_assert(false, "BYTE_ORDER is undefined. Perhaps, GNU extensions are not enabled");
#endif
diff --git a/src/common/rpc_client.h b/src/common/rpc_client.h
index 64c84ed19..9665966ae 100644
--- a/src/common/rpc_client.h
+++ b/src/common/rpc_client.h
@@ -72,10 +72,10 @@ namespace tools
fail_msg_writer() << "Couldn't connect to daemon: " << m_http_client.get_host() << ":" << m_http_client.get_port();
return false;
}
- ok = ok && epee::net_utils::invoke_http_json_rpc("/json_rpc", method_name, req, res, m_http_client, t_http_connection::TIMEOUT());
+ ok = epee::net_utils::invoke_http_json_rpc("/json_rpc", method_name, req, res, m_http_client, t_http_connection::TIMEOUT());
if (!ok)
{
- fail_msg_writer() << "Daemon request failed";
+ fail_msg_writer() << "basic_json_rpc_request: Daemon request failed";
return false;
}
else
@@ -95,15 +95,15 @@ namespace tools
t_http_connection connection(&m_http_client);
bool ok = connection.is_open();
- ok = ok && epee::net_utils::invoke_http_json_rpc("/json_rpc", method_name, req, res, m_http_client, t_http_connection::TIMEOUT());
if (!ok)
{
fail_msg_writer() << "Couldn't connect to daemon: " << m_http_client.get_host() << ":" << m_http_client.get_port();
return false;
}
- else if (res.status != CORE_RPC_STATUS_OK) // TODO - handle CORE_RPC_STATUS_BUSY ?
+ ok = epee::net_utils::invoke_http_json_rpc("/json_rpc", method_name, req, res, m_http_client, t_http_connection::TIMEOUT());
+ if (!ok || res.status != CORE_RPC_STATUS_OK) // TODO - handle CORE_RPC_STATUS_BUSY ?
{
- fail_msg_writer() << fail_msg << " -- " << res.status;
+ fail_msg_writer() << fail_msg << " -- json_rpc_request: " << res.status;
return false;
}
else
@@ -123,15 +123,15 @@ namespace tools
t_http_connection connection(&m_http_client);
bool ok = connection.is_open();
- ok = ok && epee::net_utils::invoke_http_json(relative_url, req, res, m_http_client, t_http_connection::TIMEOUT());
if (!ok)
{
fail_msg_writer() << "Couldn't connect to daemon: " << m_http_client.get_host() << ":" << m_http_client.get_port();
return false;
}
- else if (res.status != CORE_RPC_STATUS_OK) // TODO - handle CORE_RPC_STATUS_BUSY ?
+ ok = epee::net_utils::invoke_http_json(relative_url, req, res, m_http_client, t_http_connection::TIMEOUT());
+ if (!ok || res.status != CORE_RPC_STATUS_OK) // TODO - handle CORE_RPC_STATUS_BUSY ?
{
- fail_msg_writer() << fail_msg << " -- " << res.status;
+ fail_msg_writer() << fail_msg << "-- rpc_request: " << res.status;
return false;
}
else
diff --git a/src/crypto/chacha.c b/src/crypto/chacha.c
index f573083be..5d3edb98d 100644
--- a/src/crypto/chacha.c
+++ b/src/crypto/chacha.c
@@ -6,7 +6,9 @@ Public domain.
#include <memory.h>
#include <stdio.h>
+#ifndef _MSC_VER
#include <sys/param.h>
+#endif
#include "chacha.h"
#include "common/int-util.h"
diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp
index b28854a13..d9b8b6787 100644
--- a/src/crypto/crypto.cpp
+++ b/src/crypto/crypto.cpp
@@ -28,6 +28,7 @@
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+#include <unistd.h>
#include <cassert>
#include <cstddef>
#include <cstdint>
@@ -43,6 +44,18 @@
#include "crypto.h"
#include "hash.h"
+namespace {
+ static void local_abort(const char *msg)
+ {
+ fprintf(stderr, "%s\n", msg);
+#ifdef NDEBUG
+ _exit(1);
+#else
+ abort();
+#endif
+ }
+}
+
namespace crypto {
using std::abort;
@@ -467,7 +480,7 @@ POP_WARNINGS
ec_scalar sum, k, h;
boost::shared_ptr<rs_comm> buf(reinterpret_cast<rs_comm *>(malloc(rs_comm_size(pubs_count))), free);
if (!buf)
- abort();
+ local_abort("malloc failure");
assert(sec_index < pubs_count);
#if !defined(NDEBUG)
{
@@ -486,7 +499,7 @@ POP_WARNINGS
}
#endif
if (ge_frombytes_vartime(&image_unp, &image) != 0) {
- abort();
+ local_abort("invalid key image");
}
ge_dsm_precomp(image_pre, &image_unp);
sc_0(&sum);
@@ -505,7 +518,7 @@ POP_WARNINGS
random_scalar(sig[i].c);
random_scalar(sig[i].r);
if (ge_frombytes_vartime(&tmp3, &*pubs[i]) != 0) {
- abort();
+ local_abort("invalid pubkey");
}
ge_double_scalarmult_base_vartime(&tmp2, &sig[i].c, &tmp3, &sig[i].r);
ge_tobytes(&buf->ab[i].a, &tmp2);
diff --git a/src/crypto/keccak.c b/src/crypto/keccak.c
index fc6d487c2..528a5406b 100644
--- a/src/crypto/keccak.c
+++ b/src/crypto/keccak.c
@@ -4,9 +4,20 @@
#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
#include "hash-ops.h"
#include "keccak.h"
+static void local_abort(const char *msg)
+{
+ fprintf(stderr, "%s\n", msg);
+#ifdef NDEBUG
+ _exit(1);
+#else
+ abort();
+#endif
+}
+
const uint64_t keccakf_rndc[24] =
{
0x0000000000000001, 0x0000000000008082, 0x800000000000808a,
@@ -83,8 +94,7 @@ void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen)
if (mdlen <= 0 || mdlen > 200 || sizeof(st) != 200)
{
- fprintf(stderr, "Bad keccak use");
- abort();
+ local_abort("Bad keccak use");
}
rsiz = sizeof(state_t) == mdlen ? HASH_DATA_AREA : 200 - 2 * mdlen;
@@ -101,8 +111,7 @@ void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen)
// last block and padding
if (inlen >= sizeof(temp) || inlen > rsiz || rsiz - inlen + inlen + 1 >= sizeof(temp) || rsiz == 0 || rsiz - 1 >= sizeof(temp) || rsizw * 8 > sizeof(temp))
{
- fprintf(stderr, "Bad keccak use");
- abort();
+ local_abort("Bad keccak use");
}
memcpy(temp, in, inlen);
diff --git a/src/crypto/oaes_lib.c b/src/crypto/oaes_lib.c
index 0afec6212..9e31ebf46 100644
--- a/src/crypto/oaes_lib.c
+++ b/src/crypto/oaes_lib.c
@@ -53,6 +53,12 @@
#include <unistd.h>
#endif
+#ifdef _MSC_VER
+#define GETPID() _getpid()
+#else
+#define GETPID() getpid()
+#endif
+
#include "oaes_config.h"
#include "oaes_lib.h"
@@ -478,7 +484,7 @@ static void oaes_get_seed( char buf[RANDSIZ + 1] )
sprintf( buf, "%04d%02d%02d%02d%02d%02d%03d%p%d",
gmTimer->tm_year + 1900, gmTimer->tm_mon + 1, gmTimer->tm_mday,
gmTimer->tm_hour, gmTimer->tm_min, gmTimer->tm_sec, timer.millitm,
- _test + timer.millitm, getpid() );
+ _test + timer.millitm, GETPID() );
#else
struct timeval timer;
struct tm *gmTimer;
@@ -490,7 +496,7 @@ static void oaes_get_seed( char buf[RANDSIZ + 1] )
sprintf( buf, "%04d%02d%02d%02d%02d%02d%03d%p%d",
gmTimer->tm_year + 1900, gmTimer->tm_mon + 1, gmTimer->tm_mday,
gmTimer->tm_hour, gmTimer->tm_min, gmTimer->tm_sec, timer.tv_usec/1000,
- _test + timer.tv_usec/1000, getpid() );
+ _test + timer.tv_usec/1000, GETPID() );
#endif
if( _test )
@@ -510,7 +516,7 @@ static uint32_t oaes_get_seed(void)
_test = (char *) calloc( sizeof( char ), timer.millitm );
_ret = gmTimer->tm_year + 1900 + gmTimer->tm_mon + 1 + gmTimer->tm_mday +
gmTimer->tm_hour + gmTimer->tm_min + gmTimer->tm_sec + timer.millitm +
- (uintptr_t) ( _test + timer.millitm ) + getpid();
+ (uintptr_t) ( _test + timer.millitm ) + GETPID();
#else
struct timeval timer;
struct tm *gmTimer;
@@ -522,7 +528,7 @@ static uint32_t oaes_get_seed(void)
_test = (char *) calloc( sizeof( char ), timer.tv_usec/1000 );
_ret = gmTimer->tm_year + 1900 + gmTimer->tm_mon + 1 + gmTimer->tm_mday +
gmTimer->tm_hour + gmTimer->tm_min + gmTimer->tm_sec + timer.tv_usec/1000 +
- (uintptr_t) ( _test + timer.tv_usec/1000 ) + getpid();
+ (uintptr_t) ( _test + timer.tv_usec/1000 ) + GETPID();
#endif
if( _test )
diff --git a/src/crypto/random.c b/src/crypto/random.c
index cd46a1362..929377943 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -45,7 +45,11 @@ static void generate_system_random_bytes(size_t n, void *result);
static void generate_system_random_bytes(size_t n, void *result) {
HCRYPTPROV prov;
+#ifdef NDEBUG
+#define must_succeed(x) do if (!(x)) { fprintf(stderr, "Failed: " #x); _exit(1); } while (0)
+#else
#define must_succeed(x) do if (!(x)) abort(); while (0)
+#endif
must_succeed(CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT));
must_succeed(CryptGenRandom(prov, (DWORD)n, result));
must_succeed(CryptReleaseContext(prov, 0));
diff --git a/src/crypto/tree-hash.c b/src/crypto/tree-hash.c
index 59fd20bf9..e6d6a267c 100644
--- a/src/crypto/tree-hash.c
+++ b/src/crypto/tree-hash.c
@@ -34,7 +34,9 @@
#include "hash-ops.h"
-#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
+#ifdef _MSC_VER
+#include <malloc.h>
+#elif !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
#include <alloca.h>
#else
#include <stdlib.h>
diff --git a/src/cryptonote_basic/cryptonote_boost_serialization.h b/src/cryptonote_basic/cryptonote_boost_serialization.h
index 80bd2fdc9..143133163 100644
--- a/src/cryptonote_basic/cryptonote_boost_serialization.h
+++ b/src/cryptonote_basic/cryptonote_boost_serialization.h
@@ -299,7 +299,7 @@ namespace boost
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type");
// a & x.message; message is not serialized, as it can be reconstructed from the tx data
// a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
- if (x.type == rct::RCTTypeSimple || x.type == rct::RCTTypeSimpleBulletproof)
+ if (x.type == rct::RCTTypeSimple) // moved to prunable with bulletproofs
a & x.pseudoOuts;
a & x.ecdhInfo;
serializeOutPk(a, x.outPk, ver);
@@ -313,6 +313,8 @@ namespace boost
if (x.rangeSigs.empty())
a & x.bulletproofs;
a & x.MGs;
+ if (x.rangeSigs.empty())
+ a & x.pseudoOuts;
}
template <class Archive>
@@ -325,7 +327,7 @@ namespace boost
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type");
// a & x.message; message is not serialized, as it can be reconstructed from the tx data
// a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
- if (x.type == rct::RCTTypeSimple || x.type == rct::RCTTypeSimpleBulletproof)
+ if (x.type == rct::RCTTypeSimple)
a & x.pseudoOuts;
a & x.ecdhInfo;
serializeOutPk(a, x.outPk, ver);
@@ -335,6 +337,8 @@ namespace boost
if (x.p.rangeSigs.empty())
a & x.p.bulletproofs;
a & x.p.MGs;
+ if (x.type == rct::RCTTypeSimpleBulletproof)
+ a & x.p.pseudoOuts;
}
}
}
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 178479f3c..7ee9ade80 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -127,7 +127,8 @@ static const struct {
{ 5, 802660, 0, 1472415036 + 86400*180 }, // add 5 months on testnet to shut the update warning up since there's a large gap to v6
{ 6, 971400, 0, 1501709789 },
- { 7, 1057028, 0, 1512211236 },
+ { 7, 1057027, 0, 1512211236 },
+ { 8, 1057058, 0, 1515967497 },
};
static const uint64_t testnet_hard_fork_version_1_till = 624633;
@@ -2395,11 +2396,11 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
}
}
- // from v7, allow bulletproofs
- if (hf_version < 7 || !m_testnet) {
+ // from v8, allow bulletproofs
+ if (hf_version < 8) {
if (!tx.rct_signatures.p.bulletproofs.empty())
{
- MERROR("Bulletproofs are not allowed before v7 or on mainnet");
+ MERROR("Bulletproofs are not allowed before v8");
tvc.m_invalid_output = true;
return false;
}
diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp
index 431d71556..4a10f7133 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.cpp
+++ b/src/cryptonote_core/cryptonote_tx_utils.cpp
@@ -172,20 +172,24 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
- crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const account_keys &sender_keys)
+ crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const boost::optional<cryptonote::account_public_address>& change_addr)
{
- if (destinations.empty())
- return null_pkey;
- for (size_t n = 1; n < destinations.size(); ++n)
+ account_public_address addr = {null_pkey, null_pkey};
+ size_t count = 0;
+ for (const auto &i : destinations)
{
- if (!memcmp(&destinations[n].addr, &sender_keys.m_account_address, sizeof(destinations[0].addr)))
+ if (i.amount == 0)
continue;
- if (destinations[n].amount == 0)
+ if (change_addr && i.addr == *change_addr)
continue;
- if (memcmp(&destinations[n].addr, &destinations[0].addr, sizeof(destinations[0].addr)))
+ if (i.addr == addr)
+ continue;
+ if (count > 0)
return null_pkey;
+ addr = i.addr;
+ ++count;
}
- return destinations[0].addr.m_view_public_key;
+ return addr.m_view_public_key;
}
//---------------------------------------------------------------
bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct, bool bulletproof, rct::multisig_out *msout)
@@ -221,7 +225,7 @@ namespace cryptonote
if (get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id))
{
LOG_PRINT_L2("Encrypting payment id " << payment_id);
- crypto::public_key view_key_pub = get_destination_view_key_pub(destinations, sender_account_keys);
+ crypto::public_key view_key_pub = get_destination_view_key_pub(destinations, change_addr);
if (view_key_pub == null_pkey)
{
LOG_ERROR("Destinations have to have exactly one output to support encrypted payment ids");
diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h
index e3b7a4f8c..1c390078d 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.h
+++ b/src/cryptonote_core/cryptonote_tx_utils.h
@@ -88,7 +88,7 @@ namespace cryptonote
};
//---------------------------------------------------------------
- crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const account_keys &sender_keys);
+ crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const boost::optional<cryptonote::account_public_address>& change_addr);
bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry> &sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time);
bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, bool bulletproof = false, rct::multisig_out *msout = NULL);
bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, bool bulletproof = false, rct::multisig_out *msout = NULL);
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h
index cbb8273e9..e24c964a5 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h
@@ -79,7 +79,7 @@ namespace cryptonote
typedef t_cryptonote_protocol_handler<t_core> cryptonote_protocol_handler;
typedef CORE_SYNC_DATA payload_type;
- t_cryptonote_protocol_handler(t_core& rcore, nodetool::i_p2p_endpoint<connection_context>* p_net_layout);
+ t_cryptonote_protocol_handler(t_core& rcore, nodetool::i_p2p_endpoint<connection_context>* p_net_layout, bool offline = false);
BEGIN_INVOKE_MAP2(cryptonote_protocol_handler)
HANDLE_NOTIFY_T2(NOTIFY_NEW_BLOCK, &cryptonote_protocol_handler::handle_notify_new_block)
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 712d47282..9475bcaa8 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -61,10 +61,10 @@ namespace cryptonote
//-----------------------------------------------------------------------------------------------------------------------
template<class t_core>
- t_cryptonote_protocol_handler<t_core>::t_cryptonote_protocol_handler(t_core& rcore, nodetool::i_p2p_endpoint<connection_context>* p_net_layout):m_core(rcore),
+ t_cryptonote_protocol_handler<t_core>::t_cryptonote_protocol_handler(t_core& rcore, nodetool::i_p2p_endpoint<connection_context>* p_net_layout, bool offline):m_core(rcore),
m_p2p(p_net_layout),
m_syncronized_connections_count(0),
- m_synchronized(false),
+ m_synchronized(offline),
m_stopping(false)
{
@@ -445,7 +445,7 @@ namespace cryptonote
//
// Also, remember to pepper some whitespace changes around to bother
// moneromooo ... only because I <3 him.
- std::vector<size_t> need_tx_indices;
+ std::vector<uint64_t> need_tx_indices;
transaction tx;
crypto::hash tx_hash;
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index 3ec74ff79..09e425dd1 100644
--- a/src/daemon/command_parser_executor.cpp
+++ b/src/daemon/command_parser_executor.cpp
@@ -428,6 +428,23 @@ bool t_command_parser_executor::out_peers(const std::vector<std::string>& args)
return m_executor.out_peers(limit);
}
+bool t_command_parser_executor::in_peers(const std::vector<std::string>& args)
+{
+ if (args.empty()) return false;
+
+ unsigned int limit;
+ try {
+ limit = std::stoi(args[0]);
+ }
+
+ catch(const std::exception& ex) {
+ _erro("stoi exception");
+ return false;
+ }
+
+ return m_executor.in_peers(limit);
+}
+
bool t_command_parser_executor::start_save_graph(const std::vector<std::string>& args)
{
if (!args.empty()) return false;
diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h
index 37e900b8f..2c09a4748 100644
--- a/src/daemon/command_parser_executor.h
+++ b/src/daemon/command_parser_executor.h
@@ -108,7 +108,9 @@ public:
bool set_limit_down(const std::vector<std::string>& args);
bool out_peers(const std::vector<std::string>& args);
-
+
+ bool in_peers(const std::vector<std::string>& args);
+
bool start_save_graph(const std::vector<std::string>& args);
bool stop_save_graph(const std::vector<std::string>& args);
diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp
index 1f8981fa2..a50dbea69 100644
--- a/src/daemon/command_server.cpp
+++ b/src/daemon/command_server.cpp
@@ -197,6 +197,12 @@ t_command_server::t_command_server(
, "Set the <max_number> of out peers."
);
m_command_lookup.set_handler(
+ "in_peers"
+ , std::bind(&t_command_parser_executor::in_peers, &m_parser, p::_1)
+ , "in_peers <max_number>"
+ , "Set the <max_number> of in peers."
+ );
+ m_command_lookup.set_handler(
"start_save_graph"
, std::bind(&t_command_parser_executor::start_save_graph, &m_parser, p::_1)
, "Start saving data for dr monero."
diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp
index 2d662b7d3..9b15e62ca 100644
--- a/src/daemon/daemon.cpp
+++ b/src/daemon/daemon.cpp
@@ -68,7 +68,7 @@ public:
boost::program_options::variables_map const & vm
)
: core{vm}
- , protocol{vm, core}
+ , protocol{vm, core, command_line::get_arg(vm, cryptonote::arg_offline)}
, p2p{vm, protocol}
{
// Handle circular dependencies
diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp
index f4d8fad5e..7bac2d3d8 100644
--- a/src/daemon/main.cpp
+++ b/src/daemon/main.cpp
@@ -287,7 +287,7 @@ int main(int argc, char const * argv[])
MINFO("Moving from main() into the daemonize now.");
- return daemonizer::daemonize(argc, argv, daemonize::t_executor{}, vm);
+ return daemonizer::daemonize(argc, argv, daemonize::t_executor{}, vm) ? 0 : 1;
}
catch (std::exception const & ex)
{
diff --git a/src/daemon/protocol.h b/src/daemon/protocol.h
index a251ae47c..fd1d1b638 100644
--- a/src/daemon/protocol.h
+++ b/src/daemon/protocol.h
@@ -46,9 +46,9 @@ private:
public:
t_protocol(
boost::program_options::variables_map const & vm
- , t_core & core
+ , t_core & core, bool offline = false
)
- : m_protocol{core.get(), nullptr}
+ : m_protocol{core.get(), nullptr, offline}
{
MGINFO("Initializing cryptonote protocol...");
if (!m_protocol.init(vm))
diff --git a/src/daemon/rpc.h b/src/daemon/rpc.h
index c1c2329ac..17f6c7f67 100644
--- a/src/daemon/rpc.h
+++ b/src/daemon/rpc.h
@@ -60,28 +60,28 @@ public:
)
: m_server{core.get(), p2p.get()}, m_description{description}
{
- MGINFO("Initializing " << m_description << " rpc server...");
+ MGINFO("Initializing " << m_description << " RPC server...");
if (!m_server.init(vm, restricted, testnet, port))
{
- throw std::runtime_error("Failed to initialize " + m_description + " rpc server.");
+ throw std::runtime_error("Failed to initialize " + m_description + " RPC server.");
}
- MGINFO(m_description << " rpc server initialized OK on port: " << m_server.get_binded_port());
+ MGINFO(m_description << " RPC server initialized OK on port: " << m_server.get_binded_port());
}
void run()
{
- MGINFO("Starting " << m_description << " rpc server...");
+ MGINFO("Starting " << m_description << " RPC server...");
if (!m_server.run(2, false))
{
- throw std::runtime_error("Failed to start " + m_description + " rpc server.");
+ throw std::runtime_error("Failed to start " + m_description + " RPC server.");
}
- MGINFO(m_description << " rpc server started ok");
+ MGINFO(m_description << " RPC server started ok");
}
void stop()
{
- MGINFO("Stopping " << m_description << " rpc server...");
+ MGINFO("Stopping " << m_description << " RPC server...");
m_server.send_stop_signal();
m_server.timed_wait_server_stop(5000);
}
@@ -93,11 +93,11 @@ public:
~t_rpc()
{
- MGINFO("Deinitializing " << m_description << " rpc server...");
+ MGINFO("Deinitializing " << m_description << " RPC server...");
try {
m_server.deinit();
} catch (...) {
- MERROR("Failed to deinitialize " << m_description << " rpc server...");
+ MERROR("Failed to deinitialize " << m_description << " RPC server...");
}
}
};
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 2da4f3e6e..5ef799d40 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -353,15 +353,18 @@ static std::string get_fork_extra_info(uint64_t t, uint64_t now, uint64_t block_
return "";
}
-static float get_sync_percentage(const cryptonote::COMMAND_RPC_GET_INFO::response &ires)
+static float get_sync_percentage(uint64_t height, uint64_t target_height)
{
- uint64_t height = ires.height;
- uint64_t target_height = ires.target_height ? ires.target_height < ires.height ? ires.height : ires.target_height : ires.height;
+ target_height = target_height ? target_height < height ? height : target_height : height;
float pc = 100.0f * height / target_height;
if (height < target_height && pc > 99.9f)
return 99.9f; // to avoid 100% when not fully synced
return pc;
}
+static float get_sync_percentage(const cryptonote::COMMAND_RPC_GET_INFO::response &ires)
+{
+ return get_sync_percentage(ires.height, ires.target_height);
+}
bool t_rpc_command_executor::show_status() {
cryptonote::COMMAND_RPC_GET_INFO::request ireq;
@@ -421,12 +424,26 @@ bool t_rpc_command_executor::show_status() {
std::time_t uptime = std::time(nullptr) - ires.start_time;
uint64_t net_height = ires.target_height > ires.height ? ires.target_height : ires.height;
+ std::string bootstrap_msg;
+ if (ires.was_bootstrap_ever_used)
+ {
+ bootstrap_msg = ", bootstrapping from " + ires.bootstrap_daemon_address;
+ if (ires.untrusted)
+ {
+ bootstrap_msg += (boost::format(", local height: %llu (%.1f%%)") % ires.height_without_bootstrap % get_sync_percentage(ires.height_without_bootstrap, net_height)).str();
+ }
+ else
+ {
+ bootstrap_msg += " was used before";
+ }
+ }
- tools::success_msg_writer() << boost::format("Height: %llu/%llu (%.1f%%) on %s, %s, net hash %s, v%u%s, %s, %u(out)+%u(in) connections, uptime %ud %uh %um %us")
+ tools::success_msg_writer() << boost::format("Height: %llu/%llu (%.1f%%) on %s%s, %s, net hash %s, v%u%s, %s, %u(out)+%u(in) connections, uptime %ud %uh %um %us")
% (unsigned long long)ires.height
% (unsigned long long)net_height
% get_sync_percentage(ires)
% (ires.testnet ? "testnet" : "mainnet")
+ % bootstrap_msg
% (!has_mining_info ? "mining info unavailable" : mining_busy ? "syncing" : mres.active ? ( ( mres.is_background_mining_enabled ? "smart " : "" ) + std::string("mining at ") + get_mining_speed(mres.speed) ) : "not mining")
% get_mining_speed(ires.difficulty / ires.target)
% (unsigned)hfres.version
@@ -1262,7 +1279,7 @@ bool t_rpc_command_executor::out_peers(uint64_t limit)
if (m_is_rpc)
{
- if (!m_rpc_client->json_rpc_request(req, res, "out_peers", fail_message.c_str()))
+ if (!m_rpc_client->rpc_request(req, res, "/out_peers", fail_message.c_str()))
{
return true;
}
@@ -1281,6 +1298,38 @@ bool t_rpc_command_executor::out_peers(uint64_t limit)
return true;
}
+bool t_rpc_command_executor::in_peers(uint64_t limit)
+{
+ cryptonote::COMMAND_RPC_IN_PEERS::request req;
+ cryptonote::COMMAND_RPC_IN_PEERS::response res;
+
+ epee::json_rpc::error error_resp;
+
+ req.in_peers = limit;
+
+ std::string fail_message = "Unsuccessful";
+
+ if (m_is_rpc)
+ {
+ if (!m_rpc_client->rpc_request(req, res, "/in_peers", fail_message.c_str()))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (!m_rpc_server->on_in_peers(req, res) || res.status != CORE_RPC_STATUS_OK)
+ {
+ tools::fail_msg_writer() << make_error(fail_message, res.status);
+ return true;
+ }
+ }
+
+ std::cout << "Max number of in peers set to " << limit << std::endl;
+
+ return true;
+}
+
bool t_rpc_command_executor::start_save_graph()
{
cryptonote::COMMAND_RPC_START_SAVE_GRAPH::request req;
diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h
index f0781180a..fa83d8988 100644
--- a/src/daemon/rpc_command_executor.h
+++ b/src/daemon/rpc_command_executor.h
@@ -122,7 +122,9 @@ public:
bool set_limit(int64_t limit_down, int64_t limit_up);
bool out_peers(uint64_t limit);
-
+
+ bool in_peers(uint64_t limit);
+
bool start_save_graph();
bool stop_save_graph();
diff --git a/src/p2p/net_node.cpp b/src/p2p/net_node.cpp
index 121e72392..994941168 100644
--- a/src/p2p/net_node.cpp
+++ b/src/p2p/net_node.cpp
@@ -55,6 +55,7 @@ namespace nodetool
const command_line::arg_descriptor<bool> arg_no_igd = {"no-igd", "Disable UPnP port mapping"};
const command_line::arg_descriptor<int64_t> arg_out_peers = {"out-peers", "set max number of out peers", -1};
+ const command_line::arg_descriptor<int64_t> arg_in_peers = {"in-peers", "set max number of in peers", -1};
const command_line::arg_descriptor<int> arg_tos_flag = {"tos-flag", "set TOS flag", -1};
const command_line::arg_descriptor<int64_t> arg_limit_rate_up = {"limit-rate-up", "set limit-rate-up [kB/s]", -1};
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index 20520f83c..568c650cc 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -81,6 +81,7 @@ namespace nodetool
node_server(t_payload_net_handler& payload_handler)
:m_payload_handler(payload_handler),
m_current_number_of_out_peers(0),
+ m_current_number_of_in_peers(0),
m_allow_local_ip(false),
m_hide_my_port(false),
m_no_igd(false),
@@ -117,8 +118,10 @@ namespace nodetool
bool log_connections();
virtual uint64_t get_connections_count();
size_t get_outgoing_connections_count();
+ size_t get_incoming_connections_count();
peerlist_manager& get_peerlist_manager(){return m_peerlist;}
- void delete_connections(size_t count);
+ void delete_out_connections(size_t count);
+ void delete_in_connections(size_t count);
virtual bool block_host(const epee::net_utils::network_address &adress, time_t seconds = P2P_IP_BLOCKTIME);
virtual bool unblock_host(const epee::net_utils::network_address &address);
virtual std::map<std::string, time_t> get_blocked_hosts() { CRITICAL_REGION_LOCAL(m_blocked_hosts_lock); return m_blocked_hosts; }
@@ -230,6 +233,7 @@ namespace nodetool
bool parse_peers_and_add_to_container(const boost::program_options::variables_map& vm, const command_line::arg_descriptor<std::vector<std::string> > & arg, Container& container);
bool set_max_out_peers(const boost::program_options::variables_map& vm, int64_t max);
+ bool set_max_in_peers(const boost::program_options::variables_map& vm, int64_t max);
bool set_tos_flag(const boost::program_options::variables_map& vm, int limit);
bool set_rate_up_limit(const boost::program_options::variables_map& vm, int64_t limit);
@@ -271,6 +275,7 @@ namespace nodetool
public:
config m_config; // TODO was private, add getters?
std::atomic<unsigned int> m_current_number_of_out_peers;
+ std::atomic<unsigned int> m_current_number_of_in_peers;
void set_save_graph(bool save_graph)
{
@@ -345,6 +350,7 @@ namespace nodetool
extern const command_line::arg_descriptor<bool> arg_no_igd;
extern const command_line::arg_descriptor<bool> arg_offline;
extern const command_line::arg_descriptor<int64_t> arg_out_peers;
+ extern const command_line::arg_descriptor<int64_t> arg_in_peers;
extern const command_line::arg_descriptor<int> arg_tos_flag;
extern const command_line::arg_descriptor<int64_t> arg_limit_rate_up;
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index 152dba942..3445674f6 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -85,6 +85,7 @@ namespace nodetool
command_line::add_arg(desc, arg_p2p_hide_my_port);
command_line::add_arg(desc, arg_no_igd);
command_line::add_arg(desc, arg_out_peers);
+ command_line::add_arg(desc, arg_in_peers);
command_line::add_arg(desc, arg_tos_flag);
command_line::add_arg(desc, arg_limit_rate_up);
command_line::add_arg(desc, arg_limit_rate_down);
@@ -315,6 +316,9 @@ namespace nodetool
if ( !set_max_out_peers(vm, command_line::get_arg(vm, arg_out_peers) ) )
return false;
+ if ( !set_max_in_peers(vm, command_line::get_arg(vm, arg_in_peers) ) )
+ return false;
+
if ( !set_tos_flag(vm, command_line::get_arg(vm, arg_tos_flag) ) )
return false;
@@ -565,14 +569,23 @@ namespace nodetool
while (!is_closing && !m_net_server.is_stop_signal_sent())
{ // main loop of thread
//number_of_peers = m_net_server.get_config_object().get_connections_count();
- unsigned int number_of_peers = 0;
+ unsigned int number_of_in_peers = 0;
+ unsigned int number_of_out_peers = 0;
m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
{
- if (!cntxt.m_is_income) ++number_of_peers;
+ if (cntxt.m_is_income)
+ {
+ ++number_of_in_peers;
+ }
+ else
+ {
+ ++number_of_out_peers;
+ }
return true;
}); // lambda
- m_current_number_of_out_peers = number_of_peers;
+ m_current_number_of_in_peers = number_of_in_peers;
+ m_current_number_of_out_peers = number_of_out_peers;
boost::this_thread::sleep_for(boost::chrono::seconds(1));
} // main loop of thread
@@ -871,11 +884,11 @@ namespace nodetool
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::try_to_connect_and_handshake_with_new_peer(const epee::net_utils::network_address& na, bool just_take_peerlist, uint64_t last_seen_stamp, PeerType peer_type, uint64_t first_seen_stamp)
{
- if (m_current_number_of_out_peers == m_config.m_net_config.connections_count) // out peers limit
+ if (m_current_number_of_out_peers == m_config.m_net_config.max_out_connection_count) // out peers limit
{
return false;
}
- else if (m_current_number_of_out_peers > m_config.m_net_config.connections_count)
+ else if (m_current_number_of_out_peers > m_config.m_net_config.max_out_connection_count)
{
m_net_server.get_config_object().del_out_connections(1);
m_current_number_of_out_peers --; // atomic variable, update time = 1s
@@ -1164,10 +1177,10 @@ namespace nodetool
if (!connect_to_peerlist(m_priority_peers)) return false;
- size_t expected_white_connections = (m_config.m_net_config.connections_count*P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT)/100;
+ size_t expected_white_connections = (m_config.m_net_config.max_out_connection_count*P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT)/100;
size_t conn_count = get_outgoing_connections_count();
- if(conn_count < m_config.m_net_config.connections_count)
+ if(conn_count < m_config.m_net_config.max_out_connection_count)
{
if(conn_count < expected_white_connections)
{
@@ -1178,20 +1191,20 @@ namespace nodetool
if(!make_expected_connections_count(white, expected_white_connections))
return false;
//then do grey list
- if(!make_expected_connections_count(gray, m_config.m_net_config.connections_count))
+ if(!make_expected_connections_count(gray, m_config.m_net_config.max_out_connection_count))
return false;
}else
{
//start from grey list
- if(!make_expected_connections_count(gray, m_config.m_net_config.connections_count))
+ if(!make_expected_connections_count(gray, m_config.m_net_config.max_out_connection_count))
return false;
//and then do white list
- if(!make_expected_connections_count(white, m_config.m_net_config.connections_count))
+ if(!make_expected_connections_count(white, m_config.m_net_config.max_out_connection_count))
return false;
}
}
- if (start_conn_count == get_outgoing_connections_count() && start_conn_count < m_config.m_net_config.connections_count)
+ if (start_conn_count == get_outgoing_connections_count() && start_conn_count < m_config.m_net_config.max_out_connection_count)
{
MINFO("Failed to connect to any, trying seeds");
if (!connect_to_seed())
@@ -1253,6 +1266,20 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
+ size_t node_server<t_payload_net_handler>::get_incoming_connections_count()
+ {
+ size_t count = 0;
+ m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
+ {
+ if(cntxt.m_is_income)
+ ++count;
+ return true;
+ });
+
+ return count;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::idle_worker()
{
m_peer_handshake_idle_maker_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::peer_sync_idle_maker, this));
@@ -1618,6 +1645,13 @@ namespace nodetool
return 1;
}
+ if (m_current_number_of_in_peers >= m_config.m_net_config.max_in_connection_count) // in peers limit
+ {
+ LOG_WARNING_CC(context, "COMMAND_HANDSHAKE came, but already have max incoming connections, so dropping this one.");
+ drop_connection(context);
+ return 1;
+ }
+
if(!m_payload_handler.process_payload_sync_data(arg.payload_data, context, true))
{
LOG_WARNING_CC(context, "COMMAND_HANDSHAKE came, but process_payload_sync_data returned false, dropping connection.");
@@ -1779,20 +1813,37 @@ namespace nodetool
bool node_server<t_payload_net_handler>::set_max_out_peers(const boost::program_options::variables_map& vm, int64_t max)
{
if(max == -1) {
- m_config.m_net_config.connections_count = P2P_DEFAULT_CONNECTIONS_COUNT;
+ m_config.m_net_config.max_out_connection_count = P2P_DEFAULT_CONNECTIONS_COUNT;
+ return true;
+ }
+ m_config.m_net_config.max_out_connection_count = max;
+ return true;
+ }
+
+ template<class t_payload_net_handler>
+ bool node_server<t_payload_net_handler>::set_max_in_peers(const boost::program_options::variables_map& vm, int64_t max)
+ {
+ if(max == -1) {
+ m_config.m_net_config.max_in_connection_count = -1;
return true;
}
- m_config.m_net_config.connections_count = max;
+ m_config.m_net_config.max_in_connection_count = max;
return true;
}
template<class t_payload_net_handler>
- void node_server<t_payload_net_handler>::delete_connections(size_t count)
+ void node_server<t_payload_net_handler>::delete_out_connections(size_t count)
{
m_net_server.get_config_object().del_out_connections(count);
}
template<class t_payload_net_handler>
+ void node_server<t_payload_net_handler>::delete_in_connections(size_t count)
+ {
+ m_net_server.get_config_object().del_in_connections(count);
+ }
+
+ template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::set_tos_flag(const boost::program_options::variables_map& vm, int flag)
{
if(flag==-1){
diff --git a/src/p2p/p2p_protocol_defs.h b/src/p2p/p2p_protocol_defs.h
index 348a8b978..e793e19b6 100644
--- a/src/p2p/p2p_protocol_defs.h
+++ b/src/p2p/p2p_protocol_defs.h
@@ -131,13 +131,15 @@ namespace nodetool
struct network_config
{
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(connections_count)
+ KV_SERIALIZE(max_out_connection_count)
+ KV_SERIALIZE(max_in_connection_count)
KV_SERIALIZE(handshake_interval)
KV_SERIALIZE(packet_max_size)
KV_SERIALIZE(config_id)
END_KV_SERIALIZE_MAP()
- uint32_t connections_count;
+ uint32_t max_out_connection_count;
+ uint32_t max_in_connection_count;
uint32_t connection_timeout;
uint32_t ping_connection_timeout;
uint32_t handshake_interval;
diff --git a/src/ringct/bulletproofs.cc b/src/ringct/bulletproofs.cc
index 67e877326..fd15ffbc4 100644
--- a/src/ringct/bulletproofs.cc
+++ b/src/ringct/bulletproofs.cc
@@ -297,6 +297,39 @@ static rct::keyV slice(const rct::keyV &a, size_t start, size_t stop)
return res;
}
+static rct::key hash_cache_mash(rct::key &hash_cache, const rct::key &mash0, const rct::key &mash1)
+{
+ rct::keyV data;
+ data.reserve(3);
+ data.push_back(hash_cache);
+ data.push_back(mash0);
+ data.push_back(mash1);
+ return hash_cache = rct::hash_to_scalar(data);
+}
+
+static rct::key hash_cache_mash(rct::key &hash_cache, const rct::key &mash0, const rct::key &mash1, const rct::key &mash2)
+{
+ rct::keyV data;
+ data.reserve(4);
+ data.push_back(hash_cache);
+ data.push_back(mash0);
+ data.push_back(mash1);
+ data.push_back(mash2);
+ return hash_cache = rct::hash_to_scalar(data);
+}
+
+static rct::key hash_cache_mash(rct::key &hash_cache, const rct::key &mash0, const rct::key &mash1, const rct::key &mash2, const rct::key &mash3)
+{
+ rct::keyV data;
+ data.reserve(5);
+ data.push_back(hash_cache);
+ data.push_back(mash0);
+ data.push_back(mash1);
+ data.push_back(mash2);
+ data.push_back(mash3);
+ return hash_cache = rct::hash_to_scalar(data);
+}
+
/* Given a value v (0..2^N-1) and a mask gamma, construct a range proof */
Bulletproof bulletproof_PROVE(const rct::key &sv, const rct::key &gamma)
{
@@ -329,6 +362,7 @@ Bulletproof bulletproof_PROVE(const rct::key &sv, const rct::key &gamma)
}
PERF_TIMER_STOP(PROVE_aLaR);
+ rct::key hash_cache = rct::hash_to_scalar(V);
// DEBUG: Test to ensure this recovers the value
#ifdef DEBUG_BP
@@ -361,11 +395,8 @@ Bulletproof bulletproof_PROVE(const rct::key &sv, const rct::key &gamma)
rct::addKeys(S, ve, rct::scalarmultBase(rho));
// PAPER LINES 43-45
- rct::keyV hashed;
- hashed.push_back(A);
- hashed.push_back(S);
- rct::key y = rct::hash_to_scalar(hashed);
- rct::key z = rct::hash_to_scalar(y);
+ rct::key y = hash_cache_mash(hash_cache, A, S);
+ rct::key z = hash_cache = rct::hash_to_scalar(y);
// Polynomial construction before PAPER LINE 46
rct::key t0 = rct::zero();
@@ -427,11 +458,7 @@ Bulletproof bulletproof_PROVE(const rct::key &sv, const rct::key &gamma)
rct::key T2 = rct::addKeys(rct::scalarmultKey(rct::H, t2), rct::scalarmultBase(tau2));
// PAPER LINES 49-51
- hashed.clear();
- hashed.push_back(z);
- hashed.push_back(T1);
- hashed.push_back(T2);
- rct::key x = rct::hash_to_scalar(hashed);
+ rct::key x = hash_cache_mash(hash_cache, z, T1, T2);
// PAPER LINES 52-53
rct::key taux = rct::zero();
@@ -460,12 +487,7 @@ Bulletproof bulletproof_PROVE(const rct::key &sv, const rct::key &gamma)
#endif
// PAPER LINES 32-33
- hashed.clear();
- hashed.push_back(x);
- hashed.push_back(taux);
- hashed.push_back(mu);
- hashed.push_back(t);
- rct::key x_ip = rct::hash_to_scalar(hashed);
+ rct::key x_ip = hash_cache_mash(hash_cache, x, taux, mu, t);
// These are used in the inner product rounds
size_t nprime = N;
@@ -509,20 +531,7 @@ Bulletproof bulletproof_PROVE(const rct::key &sv, const rct::key &gamma)
rct::addKeys(R[round], R[round], rct::scalarmultKey(rct::H, tmp));
// PAPER LINES 21-22
- hashed.clear();
- if (round == 0)
- {
- hashed.push_back(L[0]);
- hashed.push_back(R[0]);
- w[0] = rct::hash_to_scalar(hashed);
- }
- else
- {
- hashed.push_back(w[round - 1]);
- hashed.push_back(L[round]);
- hashed.push_back(R[round]);
- w[round] = rct::hash_to_scalar(hashed);
- }
+ w[round] = hash_cache_mash(hash_cache, L[round], R[round]);
// PAPER LINES 24-25
const rct::key winv = invert(w[round]);
@@ -563,6 +572,7 @@ bool bulletproof_VERIFY(const Bulletproof &proof)
{
init_exponents();
+ CHECK_AND_ASSERT_MES(proof.V.size() == 1, false, "V does not have exactly one element");
CHECK_AND_ASSERT_MES(proof.L.size() == proof.R.size(), false, "Mismatched L and R sizes");
CHECK_AND_ASSERT_MES(proof.L.size() > 0, false, "Empty proof");
CHECK_AND_ASSERT_MES(proof.L.size() == 6, false, "Proof is not for 64 bits");
@@ -573,26 +583,15 @@ bool bulletproof_VERIFY(const Bulletproof &proof)
// Reconstruct the challenges
PERF_TIMER_START_BP(VERIFY);
PERF_TIMER_START_BP(VERIFY_start);
- rct::keyV hashed;
- hashed.push_back(proof.A);
- hashed.push_back(proof.S);
- rct::key y = rct::hash_to_scalar(hashed);
- rct::key z = rct::hash_to_scalar(y);
- hashed.clear();
- hashed.push_back(z);
- hashed.push_back(proof.T1);
- hashed.push_back(proof.T2);
- rct::key x = rct::hash_to_scalar(hashed);
+ rct::key hash_cache = rct::hash_to_scalar(proof.V[0]);
+ rct::key y = hash_cache_mash(hash_cache, proof.A, proof.S);
+ rct::key z = hash_cache = rct::hash_to_scalar(y);
+ rct::key x = hash_cache_mash(hash_cache, z, proof.T1, proof.T2);
PERF_TIMER_STOP(VERIFY_start);
PERF_TIMER_START_BP(VERIFY_line_60);
// Reconstruct the challenges
- hashed.clear();
- hashed.push_back(x);
- hashed.push_back(proof.taux);
- hashed.push_back(proof.mu);
- hashed.push_back(proof.t);
- rct::key x_ip = hash_to_scalar(hashed);
+ rct::key x_ip = hash_cache_mash(hash_cache, x, proof.taux, proof.mu, proof.t);
PERF_TIMER_STOP(VERIFY_line_60);
PERF_TIMER_START_BP(VERIFY_line_61);
@@ -647,17 +646,9 @@ bool bulletproof_VERIFY(const Bulletproof &proof)
// PAPER LINES 21-22
// The inner product challenges are computed per round
rct::keyV w(rounds);
- hashed.clear();
- hashed.push_back(proof.L[0]);
- hashed.push_back(proof.R[0]);
- w[0] = rct::hash_to_scalar(hashed);
- for (size_t i = 1; i < rounds; ++i)
+ for (size_t i = 0; i < rounds; ++i)
{
- hashed.clear();
- hashed.push_back(w[i-1]);
- hashed.push_back(proof.L[i]);
- hashed.push_back(proof.R[i]);
- w[i] = rct::hash_to_scalar(hashed);
+ w[i] = hash_cache_mash(hash_cache, proof.L[i], proof.R[i]);
}
PERF_TIMER_STOP(VERIFY_line_21_22);
diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp
index 3c34a5637..0c2be5add 100644
--- a/src/ringct/rctSigs.cpp
+++ b/src/ringct/rctSigs.cpp
@@ -43,6 +43,30 @@ using namespace std;
#define MONERO_DEFAULT_LOG_CATEGORY "ringct"
namespace rct {
+ bool is_simple(int type)
+ {
+ switch (type)
+ {
+ case RCTTypeSimple:
+ case RCTTypeSimpleBulletproof:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool is_bulletproof(int type)
+ {
+ switch (type)
+ {
+ case RCTTypeSimpleBulletproof:
+ case RCTTypeFullBulletproof:
+ return true;
+ default:
+ return false;
+ }
+ }
+
Bulletproof proveRangeBulletproof(key &C, key &mask, uint64_t amount)
{
mask = rct::skGen();
@@ -357,7 +381,8 @@ namespace rct {
std::stringstream ss;
binary_archive<true> ba(ss);
- const size_t inputs = rv.pseudoOuts.size();
+ CHECK_AND_ASSERT_THROW_MES(!rv.mixRing.empty(), "Empty mixRing");
+ const size_t inputs = is_simple(rv.type) ? rv.mixRing.size() : rv.mixRing[0].size();
const size_t outputs = rv.ecdhInfo.size();
CHECK_AND_ASSERT_THROW_MES(const_cast<rctSig&>(rv).serialize_rctsig_base(ba, inputs, outputs),
"Failed to serialize rctSigBase");
@@ -750,25 +775,26 @@ namespace rct {
// TODO: unused ??
// key txnFeeKey = scalarmultH(d2h(rv.txnFee));
rv.mixRing = mixRing;
- rv.pseudoOuts.resize(inamounts.size());
+ keyV &pseudoOuts = bulletproof ? rv.p.pseudoOuts : rv.pseudoOuts;
+ pseudoOuts.resize(inamounts.size());
rv.p.MGs.resize(inamounts.size());
key sumpouts = zero(); //sum pseudoOut masks
keyV a(inamounts.size());
for (i = 0 ; i < inamounts.size() - 1; i++) {
skGen(a[i]);
sc_add(sumpouts.bytes, a[i].bytes, sumpouts.bytes);
- genC(rv.pseudoOuts[i], a[i], inamounts[i]);
+ genC(pseudoOuts[i], a[i], inamounts[i]);
}
rv.mixRing = mixRing;
sc_sub(a[i].bytes, sumout.bytes, sumpouts.bytes);
- genC(rv.pseudoOuts[i], a[i], inamounts[i]);
- DP(rv.pseudoOuts[i]);
+ genC(pseudoOuts[i], a[i], inamounts[i]);
+ DP(pseudoOuts[i]);
key full_message = get_pre_mlsag_hash(rv);
if (msout)
msout->c.resize(inamounts.size());
for (i = 0 ; i < inamounts.size(); i++) {
- rv.p.MGs[i] = proveRctMGSimple(full_message, rv.mixRing[i], inSk[i], a[i], rv.pseudoOuts[i], kLRki ? &(*kLRki)[i]: NULL, msout ? &msout->c[i] : NULL, index[i]);
+ rv.p.MGs[i] = proveRctMGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], kLRki ? &(*kLRki)[i]: NULL, msout ? &msout->c[i] : NULL, index[i]);
}
return rv;
}
@@ -876,16 +902,26 @@ namespace rct {
if (semantics)
{
if (rv.type == RCTTypeSimpleBulletproof)
+ {
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.bulletproofs.size(), false, "Mismatched sizes of outPk and rv.p.bulletproofs");
+ CHECK_AND_ASSERT_MES(rv.p.pseudoOuts.size() == rv.p.MGs.size(), false, "Mismatched sizes of rv.p.pseudoOuts and rv.p.MGs");
+ CHECK_AND_ASSERT_MES(rv.pseudoOuts.empty(), false, "rv.pseudoOuts is not empty");
+ }
else
+ {
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs");
+ CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.p.MGs.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.p.MGs");
+ CHECK_AND_ASSERT_MES(rv.p.pseudoOuts.empty(), false, "rv.p.pseudoOuts is not empty");
+ }
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo");
- CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.p.MGs.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.p.MGs");
}
else
{
// semantics check is early, and mixRing/MGs aren't resolved yet
- CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.pseudoOuts and mixRing");
+ if (rv.type == RCTTypeSimpleBulletproof)
+ CHECK_AND_ASSERT_MES(rv.p.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.p.pseudoOuts and mixRing");
+ else
+ CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.pseudoOuts and mixRing");
}
const size_t threads = std::max(rv.outPk.size(), rv.mixRing.size());
@@ -894,6 +930,8 @@ namespace rct {
tools::threadpool& tpool = tools::threadpool::getInstance();
tools::threadpool::waiter waiter;
+ const keyV &pseudoOuts = is_bulletproof(rv.type) ? rv.p.pseudoOuts : rv.pseudoOuts;
+
if (semantics) {
key sumOutpks = identity();
for (size_t i = 0; i < rv.outPk.size(); i++) {
@@ -904,8 +942,8 @@ namespace rct {
addKeys(sumOutpks, txnFeeKey, sumOutpks);
key sumPseudoOuts = identity();
- for (size_t i = 0 ; i < rv.pseudoOuts.size() ; i++) {
- addKeys(sumPseudoOuts, sumPseudoOuts, rv.pseudoOuts[i]);
+ for (size_t i = 0 ; i < pseudoOuts.size() ; i++) {
+ addKeys(sumPseudoOuts, sumPseudoOuts, pseudoOuts[i]);
}
DP(sumPseudoOuts);
@@ -941,7 +979,7 @@ namespace rct {
results.resize(rv.mixRing.size());
for (size_t i = 0 ; i < rv.mixRing.size() ; i++) {
tpool.submit(&waiter, [&, i] {
- results[i] = verRctMGSimple(message, rv.p.MGs[i], rv.mixRing[i], rv.pseudoOuts[i]);
+ results[i] = verRctMGSimple(message, rv.p.MGs[i], rv.mixRing[i], pseudoOuts[i]);
});
}
waiter.wait();
diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h
index 2df797360..eba1e3d93 100644
--- a/src/ringct/rctTypes.h
+++ b/src/ringct/rctTypes.h
@@ -246,7 +246,7 @@ namespace rct {
// inputs/outputs not saved, only here for serialization help
// FIELD(message) - not serialized, it can be reconstructed
// FIELD(mixRing) - not serialized, it can be reconstructed
- if (type == RCTTypeSimple || type == RCTTypeSimpleBulletproof)
+ if (type == RCTTypeSimple) // moved to prunable with bulletproofs
{
ar.tag("pseudoOuts");
ar.begin_array();
@@ -294,6 +294,7 @@ namespace rct {
std::vector<rangeSig> rangeSigs;
std::vector<Bulletproof> bulletproofs;
std::vector<mgSig> MGs; // simple rct has N, full has 1
+ keyV pseudoOuts; //C - for simple rct
template<bool W, template <bool> class Archive>
bool serialize_rctsig_prunable(Archive<W> &ar, uint8_t type, size_t inputs, size_t outputs, size_t mixin)
@@ -381,6 +382,21 @@ namespace rct {
ar.delimit_array();
}
ar.end_array();
+ if (type == RCTTypeSimpleBulletproof)
+ {
+ ar.tag("pseudoOuts");
+ ar.begin_array();
+ PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, pseudoOuts);
+ if (pseudoOuts.size() != inputs)
+ return false;
+ for (size_t i = 0; i < inputs; ++i)
+ {
+ FIELDS(pseudoOuts[i])
+ if (inputs - i > 1)
+ ar.delimit_array();
+ }
+ ar.end_array();
+ }
return true;
}
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 140094faa..da2e79dfa 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -42,6 +42,7 @@ using namespace epee;
#include "cryptonote_basic/account.h"
#include "cryptonote_basic/cryptonote_basic_impl.h"
#include "misc_language.h"
+#include "storages/http_abstract_invoke.h"
#include "crypto/hash.h"
#include "rpc/rpc_args.h"
#include "core_rpc_server_error_codes.h"
@@ -75,6 +76,8 @@ namespace cryptonote
command_line::add_arg(desc, arg_testnet_rpc_bind_port);
command_line::add_arg(desc, arg_testnet_rpc_restricted_bind_port);
command_line::add_arg(desc, arg_restricted_rpc);
+ command_line::add_arg(desc, arg_bootstrap_daemon_address);
+ command_line::add_arg(desc, arg_bootstrap_daemon_login);
cryptonote::rpc_args::init_options(desc);
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -101,6 +104,30 @@ namespace cryptonote
if (!rpc_config)
return false;
+ m_bootstrap_daemon_address = command_line::get_arg(vm, arg_bootstrap_daemon_address);
+ if (!m_bootstrap_daemon_address.empty())
+ {
+ const std::string &bootstrap_daemon_login = command_line::get_arg(vm, arg_bootstrap_daemon_login);
+ const auto loc = bootstrap_daemon_login.find(':');
+ if (!bootstrap_daemon_login.empty() && loc != std::string::npos)
+ {
+ epee::net_utils::http::login login;
+ login.username = bootstrap_daemon_login.substr(0, loc);
+ login.password = bootstrap_daemon_login.substr(loc + 1);
+ m_http_client.set_server(m_bootstrap_daemon_address, login, false);
+ }
+ else
+ {
+ m_http_client.set_server(m_bootstrap_daemon_address, boost::none, false);
+ }
+ m_should_use_bootstrap_daemon = true;
+ }
+ else
+ {
+ m_should_use_bootstrap_daemon = false;
+ }
+ m_was_bootstrap_ever_used = false;
+
boost::optional<epee::net_utils::http::login> http_login{};
if (rpc_config->login)
@@ -126,6 +153,10 @@ namespace cryptonote
bool core_rpc_server::on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res)
{
PERF_TIMER(on_get_height);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_HEIGHT>(invoke_http_mode::JON, "/getheight", req, res, r))
+ return r;
+
res.height = m_core.get_current_blockchain_height();
res.status = CORE_RPC_STATUS_OK;
return true;
@@ -134,6 +165,17 @@ namespace cryptonote
bool core_rpc_server::on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res)
{
PERF_TIMER(on_get_info);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_INFO>(invoke_http_mode::JON, "/getinfo", req, res, r))
+ {
+ res.bootstrap_daemon_address = m_bootstrap_daemon_address;
+ crypto::hash top_hash;
+ m_core.get_blockchain_top(res.height_without_bootstrap, top_hash);
+ ++res.height_without_bootstrap; // turn top block height into blockchain height
+ res.was_bootstrap_ever_used = true;
+ return r;
+ }
+
crypto::hash top_hash;
m_core.get_blockchain_top(res.height, top_hash);
++res.height; // turn top block height into blockchain height
@@ -158,6 +200,12 @@ namespace cryptonote
res.start_time = (uint64_t)m_core.get_start_time();
res.free_space = m_restricted ? std::numeric_limits<uint64_t>::max() : m_core.get_free_space();
res.offline = m_core.offline();
+ res.bootstrap_daemon_address = m_bootstrap_daemon_address;
+ res.height_without_bootstrap = res.height;
+ {
+ boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
+ res.was_bootstrap_ever_used = m_was_bootstrap_ever_used;
+ }
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -181,6 +229,10 @@ namespace cryptonote
bool core_rpc_server::on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res)
{
PERF_TIMER(on_get_blocks);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_FAST>(invoke_http_mode::BIN, "/getblocks.bin", req, res, r))
+ return r;
+
std::list<std::pair<cryptonote::blobdata, std::list<cryptonote::blobdata> > > bs;
if(!m_core.find_blockchain_supplement(req.start_height, req.block_ids, bs, res.current_height, res.start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT))
@@ -240,6 +292,10 @@ namespace cryptonote
bool core_rpc_server::on_get_alt_blocks_hashes(const COMMAND_RPC_GET_ALT_BLOCKS_HASHES::request& req, COMMAND_RPC_GET_ALT_BLOCKS_HASHES::response& res)
{
PERF_TIMER(on_get_alt_blocks_hashes);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_ALT_BLOCKS_HASHES>(invoke_http_mode::JON, "/get_alt_blocks_hashes", req, res, r))
+ return r;
+
std::list<block> blks;
if(!m_core.get_alternative_blocks(blks))
@@ -263,6 +319,10 @@ namespace cryptonote
bool core_rpc_server::on_get_blocks_by_height(const COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::response& res)
{
PERF_TIMER(on_get_blocks_by_height);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_BY_HEIGHT>(invoke_http_mode::BIN, "/getblocks_by_height.bin", req, res, r))
+ return r;
+
res.status = "Failed";
res.blocks.clear();
res.blocks.reserve(req.heights.size());
@@ -293,6 +353,10 @@ namespace cryptonote
bool core_rpc_server::on_get_hashes(const COMMAND_RPC_GET_HASHES_FAST::request& req, COMMAND_RPC_GET_HASHES_FAST::response& res)
{
PERF_TIMER(on_get_hashes);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_HASHES_FAST>(invoke_http_mode::BIN, "/gethashes.bin", req, res, r))
+ return r;
+
NOTIFY_RESPONSE_CHAIN_ENTRY::request resp;
resp.start_height = req.start_height;
@@ -312,6 +376,10 @@ namespace cryptonote
bool core_rpc_server::on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res)
{
PERF_TIMER(on_get_random_outs);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS>(invoke_http_mode::BIN, "/getrandom_outs.bin", req, res, r))
+ return r;
+
res.status = "Failed";
if (m_restricted)
@@ -351,6 +419,10 @@ namespace cryptonote
bool core_rpc_server::on_get_outs_bin(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMAND_RPC_GET_OUTPUTS_BIN::response& res)
{
PERF_TIMER(on_get_outs_bin);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUTS_BIN>(invoke_http_mode::BIN, "/get_outs.bin", req, res, r))
+ return r;
+
res.status = "Failed";
if (m_restricted)
@@ -374,6 +446,10 @@ namespace cryptonote
bool core_rpc_server::on_get_outs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::response& res)
{
PERF_TIMER(on_get_outs);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUTS>(invoke_http_mode::JON, "/get_outs", req, res, r))
+ return r;
+
res.status = "Failed";
if (m_restricted)
@@ -412,6 +488,10 @@ namespace cryptonote
bool core_rpc_server::on_get_random_rct_outs(const COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::request& req, COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::response& res)
{
PERF_TIMER(on_get_random_rct_outs);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS>(invoke_http_mode::BIN, "/getrandom_rctouts.bin", req, res, r))
+ return r;
+
res.status = "Failed";
if(!m_core.get_random_rct_outs(req, res))
{
@@ -436,6 +516,10 @@ namespace cryptonote
bool core_rpc_server::on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res)
{
PERF_TIMER(on_get_indexes);
+ bool ok;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES>(invoke_http_mode::BIN, "/get_o_indexes.bin", req, res, ok))
+ return ok;
+
bool r = m_core.get_tx_outputs_gindexs(req.txid, res.o_indexes);
if(!r)
{
@@ -450,6 +534,10 @@ namespace cryptonote
bool core_rpc_server::on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res)
{
PERF_TIMER(on_get_transactions);
+ bool ok;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTIONS>(invoke_http_mode::JON, "/gettransactions", req, res, ok))
+ return ok;
+
std::vector<crypto::hash> vh;
for(const auto& tx_hex_str: req.txs_hashes)
{
@@ -600,6 +688,10 @@ namespace cryptonote
bool core_rpc_server::on_is_key_image_spent(const COMMAND_RPC_IS_KEY_IMAGE_SPENT::request& req, COMMAND_RPC_IS_KEY_IMAGE_SPENT::response& res, bool request_has_rpc_origin)
{
PERF_TIMER(on_is_key_image_spent);
+ bool ok;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_IS_KEY_IMAGE_SPENT>(invoke_http_mode::JON, "/is_key_image_spent", req, res, ok))
+ return ok;
+
std::vector<crypto::key_image> key_images;
for(const auto& ki_hex_str: req.key_images)
{
@@ -663,6 +755,10 @@ namespace cryptonote
bool core_rpc_server::on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMMAND_RPC_SEND_RAW_TX::response& res)
{
PERF_TIMER(on_send_raw_tx);
+ bool ok;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_SEND_RAW_TX>(invoke_http_mode::JON, "/sendrawtransaction", req, res, ok))
+ return ok;
+
CHECK_CORE_READY();
std::string tx_blob;
@@ -886,6 +982,10 @@ namespace cryptonote
bool core_rpc_server::on_get_transaction_pool(const COMMAND_RPC_GET_TRANSACTION_POOL::request& req, COMMAND_RPC_GET_TRANSACTION_POOL::response& res, bool request_has_rpc_origin)
{
PERF_TIMER(on_get_transaction_pool);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL>(invoke_http_mode::JON, "/get_transaction_pool", req, res, r))
+ return r;
+
m_core.get_pool_transactions_and_spent_keys_info(res.transactions, res.spent_key_images, !request_has_rpc_origin || !m_restricted);
res.status = CORE_RPC_STATUS_OK;
return true;
@@ -894,6 +994,10 @@ namespace cryptonote
bool core_rpc_server::on_get_transaction_pool_hashes(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response& res, bool request_has_rpc_origin)
{
PERF_TIMER(on_get_transaction_pool_hashes);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_HASHES>(invoke_http_mode::JON, "/get_transaction_pool_hashes.bin", req, res, r))
+ return r;
+
m_core.get_pool_transaction_hashes(res.tx_hashes, !request_has_rpc_origin || !m_restricted);
res.status = CORE_RPC_STATUS_OK;
return true;
@@ -902,6 +1006,10 @@ namespace cryptonote
bool core_rpc_server::on_get_transaction_pool_stats(const COMMAND_RPC_GET_TRANSACTION_POOL_STATS::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_STATS::response& res, bool request_has_rpc_origin)
{
PERF_TIMER(on_get_transaction_pool_stats);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_STATS>(invoke_http_mode::JON, "/get_transaction_pool_stats", req, res, r))
+ return r;
+
m_core.get_pool_transaction_stats(res.pool_stats, !request_has_rpc_origin || !m_restricted);
res.status = CORE_RPC_STATUS_OK;
return true;
@@ -920,6 +1028,14 @@ namespace cryptonote
bool core_rpc_server::on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res)
{
PERF_TIMER(on_getblockcount);
+ {
+ boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
+ if (m_should_use_bootstrap_daemon)
+ {
+ res.status = "This command is unsupported for bootstrap daemon";
+ return false;
+ }
+ }
res.count = m_core.get_current_blockchain_height();
res.status = CORE_RPC_STATUS_OK;
return true;
@@ -928,6 +1044,14 @@ namespace cryptonote
bool core_rpc_server::on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_getblockhash);
+ {
+ boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
+ if (m_should_use_bootstrap_daemon)
+ {
+ res = "This command is unsupported for bootstrap daemon";
+ return false;
+ }
+ }
if(req.size() != 1)
{
error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
@@ -964,6 +1088,10 @@ namespace cryptonote
bool core_rpc_server::on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_getblocktemplate);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GETBLOCKTEMPLATE>(invoke_http_mode::JON_RPC, "getblocktemplate", req, res, r))
+ return r;
+
if(!check_core_ready())
{
error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY;
@@ -1039,6 +1167,14 @@ namespace cryptonote
bool core_rpc_server::on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_submitblock);
+ {
+ boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
+ if (m_should_use_bootstrap_daemon)
+ {
+ res.status = "This command is unsupported for bootstrap daemon";
+ return false;
+ }
+ }
CHECK_CORE_READY();
if(req.size()!=1)
{
@@ -1112,9 +1248,80 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
+ template <typename COMMAND_TYPE>
+ bool core_rpc_server::use_bootstrap_daemon_if_necessary(const invoke_http_mode &mode, const std::string &command_name, const typename COMMAND_TYPE::request& req, typename COMMAND_TYPE::response& res, bool &r)
+ {
+ res.untrusted = false;
+ if (m_bootstrap_daemon_address.empty())
+ return false;
+
+ boost::unique_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
+ if (!m_should_use_bootstrap_daemon)
+ {
+ MINFO("The local daemon is fully synced. Not switching back to the bootstrap daemon");
+ return false;
+ }
+
+ auto current_time = std::chrono::system_clock::now();
+ if (current_time - m_bootstrap_height_check_time > std::chrono::seconds(30)) // update every 30s
+ {
+ m_bootstrap_height_check_time = current_time;
+
+ uint64_t top_height;
+ crypto::hash top_hash;
+ m_core.get_blockchain_top(top_height, top_hash);
+ ++top_height; // turn top block height into blockchain height
+
+ // query bootstrap daemon's height
+ cryptonote::COMMAND_RPC_GET_HEIGHT::request getheight_req;
+ cryptonote::COMMAND_RPC_GET_HEIGHT::response getheight_res;
+ bool ok = epee::net_utils::invoke_http_json("/getheight", getheight_req, getheight_res, m_http_client);
+ ok = ok && getheight_res.status == CORE_RPC_STATUS_OK;
+
+ m_should_use_bootstrap_daemon = ok && top_height + 10 < getheight_res.height;
+ MINFO((m_should_use_bootstrap_daemon ? "Using" : "Not using") << " the bootstrap daemon (our height: " << top_height << ", bootstrap daemon's height: " << getheight_res.height << ")");
+ }
+ if (!m_should_use_bootstrap_daemon)
+ return false;
+
+ if (mode == invoke_http_mode::JON)
+ {
+ r = epee::net_utils::invoke_http_json(command_name, req, res, m_http_client);
+ }
+ else if (mode == invoke_http_mode::BIN)
+ {
+ r = epee::net_utils::invoke_http_bin(command_name, req, res, m_http_client);
+ }
+ else if (mode == invoke_http_mode::JON_RPC)
+ {
+ epee::json_rpc::request<typename COMMAND_TYPE::request> json_req = AUTO_VAL_INIT(json_req);
+ epee::json_rpc::response<typename COMMAND_TYPE::response, std::string> json_resp = AUTO_VAL_INIT(json_resp);
+ json_req.jsonrpc = "2.0";
+ json_req.id = epee::serialization::storage_entry(0);
+ json_req.method = command_name;
+ json_req.params = req;
+ r = net_utils::invoke_http_json("/json_rpc", json_req, json_resp, m_http_client);
+ if (r)
+ res = json_resp.result;
+ }
+ else
+ {
+ MERROR("Unknown invoke_http_mode: " << mode);
+ return false;
+ }
+ m_was_bootstrap_ever_used = true;
+ r = r && res.status == CORE_RPC_STATUS_OK;
+ res.untrusted = true;
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_last_block_header(const COMMAND_RPC_GET_LAST_BLOCK_HEADER::request& req, COMMAND_RPC_GET_LAST_BLOCK_HEADER::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_get_last_block_header);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_LAST_BLOCK_HEADER>(invoke_http_mode::JON_RPC, "getlastblockheader", req, res, r))
+ return r;
+
CHECK_CORE_READY();
uint64_t last_block_height;
crypto::hash last_block_hash;
@@ -1140,6 +1347,10 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_block_header_by_hash(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::response& res, epee::json_rpc::error& error_resp){
PERF_TIMER(on_get_block_header_by_hash);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH>(invoke_http_mode::JON_RPC, "getblockheaderbyhash", req, res, r))
+ return r;
+
crypto::hash block_hash;
bool hash_parsed = parse_hash256(req.hash, block_hash);
if(!hash_parsed)
@@ -1177,6 +1388,10 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_block_headers_range(const COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::request& req, COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::response& res, epee::json_rpc::error& error_resp){
PERF_TIMER(on_get_block_headers_range);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK_HEADERS_RANGE>(invoke_http_mode::JON_RPC, "getblockheadersrange", req, res, r))
+ return r;
+
const uint64_t bc_height = m_core.get_current_blockchain_height();
if (req.start_height >= bc_height || req.end_height >= bc_height || req.start_height > req.end_height)
{
@@ -1223,6 +1438,10 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_block_header_by_height(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response& res, epee::json_rpc::error& error_resp){
PERF_TIMER(on_get_block_header_by_height);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT>(invoke_http_mode::JON_RPC, "getblockheaderbyheight", req, res, r))
+ return r;
+
if(m_core.get_current_blockchain_height() <= req.height)
{
error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT;
@@ -1251,6 +1470,10 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_block(const COMMAND_RPC_GET_BLOCK::request& req, COMMAND_RPC_GET_BLOCK::response& res, epee::json_rpc::error& error_resp){
PERF_TIMER(on_get_block);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK>(invoke_http_mode::JON_RPC, "getblock", req, res, r))
+ return r;
+
crypto::hash block_hash;
if (!req.hash.empty())
{
@@ -1320,6 +1543,16 @@ namespace cryptonote
bool core_rpc_server::on_get_info_json(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_get_info_json);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_INFO>(invoke_http_mode::JON_RPC, "get_info", req, res, r))
+ {
+ res.bootstrap_daemon_address = m_bootstrap_daemon_address;
+ crypto::hash top_hash;
+ m_core.get_blockchain_top(res.height_without_bootstrap, top_hash);
+ ++res.height_without_bootstrap; // turn top block height into blockchain height
+ res.was_bootstrap_ever_used = true;
+ return r;
+ }
crypto::hash top_hash;
m_core.get_blockchain_top(res.height, top_hash);
@@ -1345,12 +1578,21 @@ namespace cryptonote
res.start_time = (uint64_t)m_core.get_start_time();
res.free_space = m_restricted ? std::numeric_limits<uint64_t>::max() : m_core.get_free_space();
res.offline = m_core.offline();
+ res.bootstrap_daemon_address = m_bootstrap_daemon_address;
+ res.height_without_bootstrap = res.height;
+ {
+ boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
+ res.was_bootstrap_ever_used = m_was_bootstrap_ever_used;
+ }
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_hard_fork_info(const COMMAND_RPC_HARD_FORK_INFO::request& req, COMMAND_RPC_HARD_FORK_INFO::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_hard_fork_info);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_HARD_FORK_INFO>(invoke_http_mode::JON_RPC, "hard_fork_info", req, res, r))
+ return r;
const Blockchain &blockchain = m_core.get_blockchain_storage();
uint8_t version = req.version > 0 ? req.version : blockchain.get_next_hard_fork_version();
@@ -1473,6 +1715,9 @@ namespace cryptonote
bool core_rpc_server::on_get_output_histogram(const COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request& req, COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_get_output_histogram);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUT_HISTOGRAM>(invoke_http_mode::JON_RPC, "get_output_histogram", req, res, r))
+ return r;
std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> histogram;
try
@@ -1500,6 +1745,10 @@ namespace cryptonote
bool core_rpc_server::on_get_version(const COMMAND_RPC_GET_VERSION::request& req, COMMAND_RPC_GET_VERSION::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_get_version);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_VERSION>(invoke_http_mode::JON_RPC, "get_version", req, res, r))
+ return r;
+
res.version = CORE_RPC_VERSION;
res.status = CORE_RPC_STATUS_OK;
return true;
@@ -1518,6 +1767,10 @@ namespace cryptonote
bool core_rpc_server::on_get_per_kb_fee_estimate(const COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE::request& req, COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_get_per_kb_fee_estimate);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE>(invoke_http_mode::JON_RPC, "get_fee_estimate", req, res, r))
+ return r;
+
res.fee = m_core.get_blockchain_storage().get_dynamic_per_kb_fee_estimate(req.grace_blocks);
res.status = CORE_RPC_STATUS_OK;
return true;
@@ -1545,6 +1798,10 @@ namespace cryptonote
bool core_rpc_server::on_get_limit(const COMMAND_RPC_GET_LIMIT::request& req, COMMAND_RPC_GET_LIMIT::response& res)
{
PERF_TIMER(on_get_limit);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_LIMIT>(invoke_http_mode::JON, "/get_limit", req, res, r))
+ return r;
+
res.limit_down = epee::net_utils::connection_basic::get_rate_down_limit();
res.limit_up = epee::net_utils::connection_basic::get_rate_up_limit();
res.status = CORE_RPC_STATUS_OK;
@@ -1596,9 +1853,21 @@ namespace cryptonote
PERF_TIMER(on_out_peers);
size_t n_connections = m_p2p.get_outgoing_connections_count();
size_t n_delete = (n_connections > req.out_peers) ? n_connections - req.out_peers : 0;
- m_p2p.m_config.m_net_config.connections_count = req.out_peers;
+ m_p2p.m_config.m_net_config.max_out_connection_count = req.out_peers;
if (n_delete)
- m_p2p.delete_connections(n_delete);
+ m_p2p.delete_out_connections(n_delete);
+ res.status = CORE_RPC_STATUS_OK;
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
+ bool core_rpc_server::on_in_peers(const COMMAND_RPC_IN_PEERS::request& req, COMMAND_RPC_IN_PEERS::response& res)
+ {
+ PERF_TIMER(on_in_peers);
+ size_t n_connections = m_p2p.get_incoming_connections_count();
+ size_t n_delete = (n_connections > req.in_peers) ? n_connections - req.in_peers : 0;
+ m_p2p.m_config.m_net_config.max_in_connection_count = req.in_peers;
+ if (n_delete)
+ m_p2p.delete_in_connections(n_delete);
res.status = CORE_RPC_STATUS_OK;
return true;
}
@@ -1790,6 +2059,9 @@ namespace cryptonote
bool core_rpc_server::on_get_txpool_backlog(const COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_get_txpool_backlog);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG>(invoke_http_mode::JON_RPC, "get_txpool_backlog", req, res, r))
+ return r;
if (!m_core.get_txpool_backlog(res.backlog))
{
@@ -1832,4 +2104,16 @@ namespace cryptonote
, "Restrict RPC to view only commands and do not return privacy sensitive data in RPC calls"
, false
};
+
+ const command_line::arg_descriptor<std::string> core_rpc_server::arg_bootstrap_daemon_address = {
+ "bootstrap-daemon-address"
+ , "URL of a 'bootstrap' remote daemon that the connected wallets can use while this daemon is still not fully synced"
+ , ""
+ };
+
+ const command_line::arg_descriptor<std::string> core_rpc_server::arg_bootstrap_daemon_login = {
+ "bootstrap-daemon-login"
+ , "Specify username:password for the bootstrap daemon login"
+ , ""
+ };
} // namespace cryptonote
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index 0c7028719..650e738bd 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -34,6 +34,7 @@
#include <boost/program_options/variables_map.hpp>
#include "net/http_server_impl_base.h"
+#include "net/http_client.h"
#include "core_rpc_server_commands_defs.h"
#include "cryptonote_core/cryptonote_core.h"
#include "p2p/net_node.h"
@@ -57,6 +58,8 @@ namespace cryptonote
static const command_line::arg_descriptor<std::string> arg_testnet_rpc_bind_port;
static const command_line::arg_descriptor<std::string> arg_testnet_rpc_restricted_bind_port;
static const command_line::arg_descriptor<bool> arg_restricted_rpc;
+ static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_address;
+ static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_login;
typedef epee::net_utils::connection_context_base connection_context;
@@ -114,6 +117,7 @@ namespace cryptonote
MAP_URI_AUTO_JON2("/get_limit", on_get_limit, COMMAND_RPC_GET_LIMIT)
MAP_URI_AUTO_JON2_IF("/set_limit", on_set_limit, COMMAND_RPC_SET_LIMIT, !m_restricted)
MAP_URI_AUTO_JON2_IF("/out_peers", on_out_peers, COMMAND_RPC_OUT_PEERS, !m_restricted)
+ MAP_URI_AUTO_JON2_IF("/in_peers", on_in_peers, COMMAND_RPC_IN_PEERS, !m_restricted)
MAP_URI_AUTO_JON2_IF("/start_save_graph", on_start_save_graph, COMMAND_RPC_START_SAVE_GRAPH, !m_restricted)
MAP_URI_AUTO_JON2_IF("/stop_save_graph", on_stop_save_graph, COMMAND_RPC_STOP_SAVE_GRAPH, !m_restricted)
MAP_URI_AUTO_JON2("/get_outs", on_get_outs, COMMAND_RPC_GET_OUTPUTS)
@@ -170,7 +174,7 @@ namespace cryptonote
bool on_get_outs_bin(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMAND_RPC_GET_OUTPUTS_BIN::response& res);
bool on_get_outs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::response& res);
bool on_get_random_rct_outs(const COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::request& req, COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::response& res);
- bool on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res);
+ bool on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res);
bool on_save_bc(const COMMAND_RPC_SAVE_BC::request& req, COMMAND_RPC_SAVE_BC::response& res);
bool on_get_peer_list(const COMMAND_RPC_GET_PEER_LIST::request& req, COMMAND_RPC_GET_PEER_LIST::response& res);
bool on_set_log_hash_rate(const COMMAND_RPC_SET_LOG_HASH_RATE::request& req, COMMAND_RPC_SET_LOG_HASH_RATE::response& res);
@@ -183,6 +187,7 @@ namespace cryptonote
bool on_get_limit(const COMMAND_RPC_GET_LIMIT::request& req, COMMAND_RPC_GET_LIMIT::response& res);
bool on_set_limit(const COMMAND_RPC_SET_LIMIT::request& req, COMMAND_RPC_SET_LIMIT::response& res);
bool on_out_peers(const COMMAND_RPC_OUT_PEERS::request& req, COMMAND_RPC_OUT_PEERS::response& res);
+ bool on_in_peers(const COMMAND_RPC_IN_PEERS::request& req, COMMAND_RPC_IN_PEERS::response& res);
bool on_start_save_graph(const COMMAND_RPC_START_SAVE_GRAPH::request& req, COMMAND_RPC_START_SAVE_GRAPH::response& res);
bool on_stop_save_graph(const COMMAND_RPC_STOP_SAVE_GRAPH::request& req, COMMAND_RPC_STOP_SAVE_GRAPH::response& res);
bool on_update(const COMMAND_RPC_UPDATE::request& req, COMMAND_RPC_UPDATE::response& res);
@@ -220,9 +225,18 @@ private:
//utils
uint64_t get_block_reward(const block& blk);
bool fill_block_header_response(const block& blk, bool orphan_status, uint64_t height, const crypto::hash& hash, block_header_response& response);
+ enum invoke_http_mode { JON, BIN, JON_RPC };
+ template <typename COMMAND_TYPE>
+ bool use_bootstrap_daemon_if_necessary(const invoke_http_mode &mode, const std::string &command_name, const typename COMMAND_TYPE::request& req, typename COMMAND_TYPE::response& res, bool &r);
core& m_core;
nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& m_p2p;
+ std::string m_bootstrap_daemon_address;
+ epee::net_utils::http::http_simple_client m_http_client;
+ boost::shared_mutex m_bootstrap_daemon_mutex;
+ bool m_should_use_bootstrap_daemon;
+ std::chrono::system_clock::time_point m_bootstrap_height_check_time;
+ bool m_was_bootstrap_ever_used;
bool m_testnet;
bool m_restricted;
};
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index 9b9a8f949..64a97f8a3 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -65,10 +65,12 @@ namespace cryptonote
{
uint64_t height;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(height)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -113,6 +115,7 @@ namespace cryptonote
uint64_t current_height;
std::string status;
std::vector<block_output_indices> output_indices;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(blocks)
@@ -120,6 +123,7 @@ namespace cryptonote
KV_SERIALIZE(current_height)
KV_SERIALIZE(status)
KV_SERIALIZE(output_indices)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -138,10 +142,12 @@ namespace cryptonote
{
std::vector<block_complete_entry> blocks;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(blocks)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -158,10 +164,12 @@ namespace cryptonote
{
std::vector<std::string> blks_hashes;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(blks_hashes)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -184,12 +192,14 @@ namespace cryptonote
uint64_t start_height;
uint64_t current_height;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_block_ids)
KV_SERIALIZE(start_height)
KV_SERIALIZE(current_height)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -595,6 +605,7 @@ namespace cryptonote
// new style
std::vector<entry> txs;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(txs_as_hex)
@@ -602,6 +613,7 @@ namespace cryptonote
KV_SERIALIZE(txs)
KV_SERIALIZE(missed_tx)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -629,10 +641,12 @@ namespace cryptonote
{
std::vector<int> spent_status;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(spent_status)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -653,9 +667,11 @@ namespace cryptonote
{
std::vector<uint64_t> o_indexes;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(o_indexes)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -695,9 +711,11 @@ namespace cryptonote
{
std::vector<outs_for_amount> outs;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(outs)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -745,10 +763,12 @@ namespace cryptonote
{
std::vector<outkey> outs;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(outs)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -785,10 +805,12 @@ namespace cryptonote
{
std::vector<outkey> outs;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(outs)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -817,9 +839,11 @@ namespace cryptonote
{
std::list<out_entry> outs;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(outs)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -854,6 +878,7 @@ namespace cryptonote
bool overspend;
bool fee_too_low;
bool not_rct;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
@@ -867,6 +892,7 @@ namespace cryptonote
KV_SERIALIZE(overspend)
KV_SERIALIZE(fee_too_low)
KV_SERIALIZE(not_rct)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -930,6 +956,10 @@ namespace cryptonote
uint64_t start_time;
uint64_t free_space;
bool offline;
+ bool untrusted;
+ std::string bootstrap_daemon_address;
+ uint64_t height_without_bootstrap;
+ bool was_bootstrap_ever_used;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
@@ -953,6 +983,10 @@ namespace cryptonote
KV_SERIALIZE(start_time)
KV_SERIALIZE(free_space)
KV_SERIALIZE(offline)
+ KV_SERIALIZE(untrusted)
+ KV_SERIALIZE(bootstrap_daemon_address)
+ KV_SERIALIZE(height_without_bootstrap)
+ KV_SERIALIZE(was_bootstrap_ever_used)
END_KV_SERIALIZE_MAP()
};
};
@@ -1080,6 +1114,7 @@ namespace cryptonote
blobdata blocktemplate_blob;
blobdata blockhashing_blob;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(difficulty)
@@ -1090,6 +1125,7 @@ namespace cryptonote
KV_SERIALIZE(blocktemplate_blob)
KV_SERIALIZE(blockhashing_blob)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -1153,10 +1189,12 @@ namespace cryptonote
{
std::string status;
block_header_response block_header;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(block_header)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
@@ -1177,10 +1215,12 @@ namespace cryptonote
{
std::string status;
block_header_response block_header;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(block_header)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
@@ -1201,10 +1241,12 @@ namespace cryptonote
{
std::string status;
block_header_response block_header;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(block_header)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
@@ -1231,6 +1273,7 @@ namespace cryptonote
std::vector<std::string> tx_hashes;
std::string blob;
std::string json;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(block_header)
@@ -1239,6 +1282,7 @@ namespace cryptonote
KV_SERIALIZE(status)
KV_SERIALIZE(blob)
KV_SERIALIZE(json)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
@@ -1415,11 +1459,13 @@ namespace cryptonote
std::string status;
std::vector<tx_info> transactions;
std::vector<spent_key_image_info> spent_key_images;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(transactions)
KV_SERIALIZE(spent_key_images)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -1436,10 +1482,12 @@ namespace cryptonote
{
std::string status;
std::vector<crypto::hash> tx_hashes;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(tx_hashes)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -1463,10 +1511,12 @@ namespace cryptonote
{
std::string status;
std::vector<tx_backlog_entry> backlog;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(backlog)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -1527,10 +1577,12 @@ namespace cryptonote
{
std::string status;
txpool_stats pool_stats;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(pool_stats)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -1573,10 +1625,12 @@ namespace cryptonote
{
std::string status;
std::vector<block_header_response> headers;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(headers)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -1630,11 +1684,13 @@ namespace cryptonote
std::string status;
uint64_t limit_up;
uint64_t limit_down;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(limit_up)
KV_SERIALIZE(limit_down)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -1678,8 +1734,28 @@ namespace cryptonote
struct response
{
- std::string status;
-
+ std::string status;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(status)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+ struct COMMAND_RPC_IN_PEERS
+ {
+ struct request
+ {
+ uint64_t in_peers;
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(in_peers)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ std::string status;
+
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
END_KV_SERIALIZE_MAP()
@@ -1744,6 +1820,7 @@ namespace cryptonote
uint32_t state;
uint64_t earliest_height;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(version)
@@ -1755,6 +1832,7 @@ namespace cryptonote
KV_SERIALIZE(state)
KV_SERIALIZE(earliest_height)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -1891,10 +1969,12 @@ namespace cryptonote
{
std::string status;
std::vector<entry> histogram;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(histogram)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -1911,10 +1991,12 @@ namespace cryptonote
{
std::string status;
uint32_t version;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(version)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -1961,10 +2043,12 @@ namespace cryptonote
{
std::string status;
uint64_t fee;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(fee)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
diff --git a/src/rpc/rpc_args.cpp b/src/rpc/rpc_args.cpp
index 6559db9b2..d4a6138ba 100644
--- a/src/rpc/rpc_args.cpp
+++ b/src/rpc/rpc_args.cpp
@@ -37,7 +37,7 @@
namespace cryptonote
{
rpc_args::descriptors::descriptors()
- : rpc_bind_ip({"rpc-bind-ip", rpc_args::tr("Specify ip to bind rpc server"), "127.0.0.1"})
+ : rpc_bind_ip({"rpc-bind-ip", rpc_args::tr("Specify IP to bind RPC server"), "127.0.0.1"})
, rpc_login({"rpc-login", rpc_args::tr("Specify username[:password] required for RPC server"), "", true})
, confirm_external_bind({"confirm-external-bind", rpc_args::tr("Confirm rpc-bind-ip value is NOT a loopback (local) IP")})
, rpc_access_control_origins({"rpc-access-control-origins", rpc_args::tr("Specify a comma separated list of origins to allow cross origin resource sharing"), ""})
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index a6cef1bb9..0a57dec80 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -158,7 +158,7 @@ namespace
boost::optional<tools::password_container> default_password_prompter(bool verify)
{
- return password_prompter(verify ? tr("Enter new wallet password") : tr("Wallet password"), verify);
+ return password_prompter(verify ? tr("Enter a new password for the wallet") : tr("Wallet password"), verify);
}
inline std::string interpret_rpc_response(bool ok, const std::string& status)
@@ -1293,7 +1293,7 @@ bool simple_wallet::set_default_priority(const std::vector<std::string> &args/*
priority = boost::lexical_cast<int>(args[1]);
if (priority < 1 || priority > 4)
{
- fail_msg_writer() << tr("priority must be 0, 1, 2, 3,or 4");
+ fail_msg_writer() << tr("priority must be 0, 1, 2, 3, or 4");
return true;
}
}
@@ -1308,7 +1308,7 @@ bool simple_wallet::set_default_priority(const std::vector<std::string> &args/*
}
catch(const boost::bad_lexical_cast &)
{
- fail_msg_writer() << tr("priority must be 0, 1, 2 3,or 4");
+ fail_msg_writer() << tr("priority must be 0, 1, 2, 3, or 4");
return true;
}
catch(...)
@@ -1589,14 +1589,14 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("transfer_original",
boost::bind(&simple_wallet::transfer, this, _1),
tr("transfer_original [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <amount> [<payment_id>]"),
- tr("Transfer <amount> to <address> using an older transaction building algorithm. If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the fee of the transaction. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
+ tr("Transfer <amount> to <address> using an older transaction building algorithm. If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer_new, this, _1),
tr("transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <amount> [<payment_id>]"),
- tr("Transfer <amount> to <address>. If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the fee of the transaction. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
+ tr("Transfer <amount> to <address>. If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
m_cmd_binder.set_handler("locked_transfer",
boost::bind(&simple_wallet::locked_transfer, this, _1),
tr("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <addr> <amount> <lockblocks> [<payment_id>]"),
- tr("Transfer <amount> to <address> and lock it for <lockblocks> (max. 1000000). If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the fee of the transaction. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
+ tr("Transfer <amount> to <address> and lock it for <lockblocks> (max. 1000000). If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
m_cmd_binder.set_handler("sweep_unmixable",
boost::bind(&simple_wallet::sweep_unmixable, this, _1),
tr("Send all unmixable outputs to yourself with ring_size 1"));
@@ -2474,7 +2474,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
r = new_wallet(vm, m_recovery_key, m_restore_deterministic_wallet, m_non_deterministic, old_language);
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
}
- if (!m_restore_height && m_restoring)
+ if (!m_wallet->explicit_refresh_from_block_height() && m_restoring)
{
uint32_t version;
bool connected = try_connect_to_daemon(false, &version);
@@ -2672,12 +2672,12 @@ std::string simple_wallet::get_mnemonic_language()
if (!((language_number >= 0) && (static_cast<unsigned int>(language_number) < language_list.size())))
{
language_number = -1;
- fail_msg_writer() << tr("invalid language choice passed. Please try again.\n");
+ fail_msg_writer() << tr("invalid language choice entered. Please try again.\n");
}
}
catch (const std::exception &e)
{
- fail_msg_writer() << tr("invalid language choice passed. Please try again.\n");
+ fail_msg_writer() << tr("invalid language choice entered. Please try again.\n");
}
}
return language_list[language_number];
@@ -3434,7 +3434,7 @@ bool simple_wallet::show_payments(const std::vector<std::string> &args)
{
if(args.empty())
{
- fail_msg_writer() << tr("expected at least one payment_id");
+ fail_msg_writer() << tr("expected at least one payment ID");
return true;
}
@@ -4578,7 +4578,7 @@ bool simple_wallet::sweep_below(const std::vector<std::string> &args_)
uint64_t below = 0;
if (args_.size() < 1)
{
- fail_msg_writer() << tr("missing amount threshold");
+ fail_msg_writer() << tr("missing threshold amount");
return true;
}
if (!cryptonote::parse_amount(below, args_[0]))
diff --git a/src/wallet/api/address_book.cpp b/src/wallet/api/address_book.cpp
index 8089a6a05..38c34a912 100644
--- a/src/wallet/api/address_book.cpp
+++ b/src/wallet/api/address_book.cpp
@@ -74,7 +74,7 @@ bool AddressBookImpl::addRow(const std::string &dst_addr , const std::string &pa
// integrated + long payment id provided
if(has_long_pid && info.has_payment_id) {
- m_errorString = tr("Integrated address and long payment id can't be used at the same time");
+ m_errorString = tr("Integrated address and long payment ID can't be used at the same time");
m_errorCode = Invalid_Payment_Id;
return false;
}
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 82948081e..f648160c9 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -626,7 +626,7 @@ bool WalletImpl::close(bool store)
if (status() != Status_Critical)
m_wallet->store();
else
- LOG_ERROR("Status_Critical - not storing wallet");
+ LOG_ERROR("Status_Critical - not saving wallet");
LOG_PRINT_L1("wallet::store done");
}
LOG_PRINT_L1("Calling wallet::stop...");
@@ -732,7 +732,7 @@ bool WalletImpl::store(const std::string &path)
m_wallet->store_to(path, m_password);
}
} catch (const std::exception &e) {
- LOG_ERROR("Error storing wallet: " << e.what());
+ LOG_ERROR("Error saving wallet: " << e.what());
m_status = Status_Error;
m_errorString = e.what();
}
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 7dc8a1e47..d97e53011 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -223,7 +223,7 @@ boost::optional<tools::password_container> get_password(const boost::program_opt
THROW_WALLET_EXCEPTION_IF(!password_prompter, tools::error::wallet_internal_error, tools::wallet2::tr("no password specified; use --prompt-for-password to prompt for a password"));
- return password_prompter(verify ? tr("Enter new wallet password") : tr("Wallet password"), verify);
+ return password_prompter(verify ? tr("Enter a new password for the wallet") : tr("Wallet password"), verify);
}
std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, const boost::program_options::variables_map& vm, const options& opts, const std::function<boost::optional<tools::password_container>(const char *, bool)> &password_prompter)
@@ -361,6 +361,7 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file,
wallet.reset(make_basic(vm, opts, password_prompter).release());
wallet->set_refresh_from_block_height(field_scan_from_height);
+ wallet->explicit_refresh_from_block_height(field_scan_from_height_found);
try
{
@@ -532,12 +533,9 @@ size_t estimate_tx_size(bool use_rct, int n_inputs, int mixin, int n_outputs, si
return n_inputs * (mixin+1) * APPROXIMATE_INPUT_BYTES + extra_size;
}
-uint8_t get_bulletproof_fork(bool testnet)
+uint8_t get_bulletproof_fork()
{
- if (testnet)
- return 7;
- else
- return 255; // TODO
+ return 8;
}
crypto::hash8 get_short_payment_id(const tools::wallet2::pending_tx &ptx)
@@ -604,6 +602,7 @@ wallet2::wallet2(bool testnet, bool restricted):
m_refresh_type(RefreshOptimizeCoinbase),
m_auto_refresh(true),
m_refresh_from_block_height(0),
+ m_explicit_refresh_from_block_height(true),
m_confirm_missing_payment_id(true),
m_ask_password(true),
m_min_output_count(0),
@@ -6642,7 +6641,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
uint64_t needed_fee, available_for_fee = 0;
uint64_t upper_transaction_size_limit = get_upper_transaction_size_limit();
const bool use_rct = use_fork_rules(4, 0);
- const bool bulletproof = use_fork_rules(get_bulletproof_fork(m_testnet), 0);
+ const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0);
const uint64_t fee_per_kb = get_per_kb_fee();
const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
@@ -7151,7 +7150,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
std::vector<std::vector<get_outs_entry>> outs;
const bool use_rct = fake_outs_count > 0 && use_fork_rules(4, 0);
- const bool bulletproof = use_fork_rules(get_bulletproof_fork(m_testnet), 0);
+ const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0);
const uint64_t fee_per_kb = get_per_kb_fee();
const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
@@ -8354,8 +8353,9 @@ uint64_t wallet2::get_approximate_blockchain_height() const
// Calculated blockchain height
uint64_t approx_blockchain_height = fork_block + (time(NULL) - fork_time)/seconds_per_block;
// testnet got some huge rollbacks, so the estimation is way off
- if (m_testnet && approx_blockchain_height > 105000)
- approx_blockchain_height -= 105000;
+ static const uint64_t approximate_testnet_rolled_back_blocks = 148540;
+ if (m_testnet && approx_blockchain_height > approximate_testnet_rolled_back_blocks)
+ approx_blockchain_height -= approximate_testnet_rolled_back_blocks;
LOG_PRINT_L2("Calculated blockchain height: " << approx_blockchain_height);
return approx_blockchain_height;
}
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index f768581b2..f9995c2ee 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -561,6 +561,9 @@ namespace tools
void set_refresh_from_block_height(uint64_t height) {m_refresh_from_block_height = height;}
uint64_t get_refresh_from_block_height() const {return m_refresh_from_block_height;}
+ void explicit_refresh_from_block_height(bool expl) {m_explicit_refresh_from_block_height = expl;}
+ bool explicit_refresh_from_block_height() const {return m_explicit_refresh_from_block_height;}
+
// upper_transaction_size_limit as defined below is set to
// approximately 125% of the fixed minimum allowable penalty
// free block size. TODO: fix this so that it actually takes
@@ -1117,6 +1120,9 @@ namespace tools
RefreshType m_refresh_type;
bool m_auto_refresh;
uint64_t m_refresh_from_block_height;
+ // If m_refresh_from_block_height is explicitly set to zero we need this to differentiate it from the case that
+ // m_refresh_from_block_height was defaulted to zero.*/
+ bool m_explicit_refresh_from_block_height;
bool m_confirm_missing_payment_id;
bool m_ask_password;
uint32_t m_min_output_count;
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 17ddee238..def7340a3 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -2932,12 +2932,12 @@ int main(int argc, char** argv) {
// if we ^C during potentially length load/refresh, there's no server loop yet
if (quit)
{
- MINFO(tools::wallet_rpc_server::tr("Storing wallet..."));
+ MINFO(tools::wallet_rpc_server::tr("Saving wallet..."));
wal->store();
- MINFO(tools::wallet_rpc_server::tr("Stored ok"));
+ MINFO(tools::wallet_rpc_server::tr("Successfully saved"));
return 1;
}
- MINFO(tools::wallet_rpc_server::tr("Loaded ok"));
+ MINFO(tools::wallet_rpc_server::tr("Successfully loaded"));
}
catch (const std::exception& e)
{
@@ -2948,11 +2948,11 @@ just_dir:
tools::wallet_rpc_server wrpc;
if (wal) wrpc.set_wallet(wal.release());
bool r = wrpc.init(&(vm.get()));
- CHECK_AND_ASSERT_MES(r, 1, tools::wallet_rpc_server::tr("Failed to initialize wallet rpc server"));
+ CHECK_AND_ASSERT_MES(r, 1, tools::wallet_rpc_server::tr("Failed to initialize wallet RPC server"));
tools::signal_handler::install([&wrpc](int) {
wrpc.send_stop_signal();
});
- LOG_PRINT_L0(tools::wallet_rpc_server::tr("Starting wallet rpc server"));
+ LOG_PRINT_L0(tools::wallet_rpc_server::tr("Starting wallet RPC server"));
try
{
wrpc.run();
@@ -2962,16 +2962,16 @@ just_dir:
LOG_ERROR(tools::wallet_rpc_server::tr("Failed to run wallet: ") << e.what());
return 1;
}
- LOG_PRINT_L0(tools::wallet_rpc_server::tr("Stopped wallet rpc server"));
+ LOG_PRINT_L0(tools::wallet_rpc_server::tr("Stopped wallet RPC server"));
try
{
- LOG_PRINT_L0(tools::wallet_rpc_server::tr("Storing wallet..."));
+ LOG_PRINT_L0(tools::wallet_rpc_server::tr("Saving wallet..."));
wrpc.stop();
- LOG_PRINT_L0(tools::wallet_rpc_server::tr("Stored ok"));
+ LOG_PRINT_L0(tools::wallet_rpc_server::tr("Successfully saved"));
}
catch (const std::exception& e)
{
- LOG_ERROR(tools::wallet_rpc_server::tr("Failed to store wallet: ") << e.what());
+ LOG_ERROR(tools::wallet_rpc_server::tr("Failed to save wallet: ") << e.what());
return 1;
}
return 0;
diff --git a/tests/fuzz/CMakeLists.txt b/tests/fuzz/CMakeLists.txt
index b15703547..6d34b13e2 100644
--- a/tests/fuzz/CMakeLists.txt
+++ b/tests/fuzz/CMakeLists.txt
@@ -143,6 +143,7 @@ target_link_libraries(http-client_fuzz_tests
PRIVATE
epee
${Boost_THREAD_LIBRARY}
+ ${Boost_CHRONO_LIBRARY}
${Boost_REGEX_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_SYSTEM_LIBRARY}
@@ -158,6 +159,7 @@ target_link_libraries(levin_fuzz_tests
common
epee
${Boost_THREAD_LIBRARY}
+ ${Boost_CHRONO_LIBRARY}
${Boost_REGEX_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
diff --git a/translations/monero.ts b/translations/monero.ts
index 27f5e1c52..5ca882bb3 100644
--- a/translations/monero.ts
+++ b/translations/monero.ts
@@ -414,7 +414,7 @@
<name>cryptonote::rpc_args</name>
<message>
<location filename="../src/rpc/rpc_args.cpp" line="38"/>
- <source>Specify ip to bind rpc server</source>
+ <source>Specify IP to bind RPC server</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -527,7 +527,7 @@
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="710"/>
- <source>sweep_below &lt;amount_threshold&gt; [mixin] address [payment_id] - Send all unlocked outputs below the threshold to an address</source>
+ <source>sweep_below &lt;amount_threshold&gt; [mixin] address [<payment_id>] - Send all unlocked outputs below the threshold to an address</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -851,7 +851,7 @@ This transaction will unlock on block %llu, in approximately %s days (assuming 2
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="2921"/>
- <source>missing amount threshold</source>
+ <source>missing threshold amount</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -896,7 +896,7 @@ This transaction will unlock on block %llu, in approximately %s days (assuming 2
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="3137"/>
- <source>daemon is busy. Please try later</source>
+ <source>daemon is busy. Please try again later</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -931,12 +931,12 @@ This transaction will unlock on block %llu, in approximately %s days (assuming 2
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="525"/>
- <source>priority must be 0, 1, 2, 3,or 4</source>
+ <source>priority must be 0, 1, 2, 3, or 4</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="540"/>
- <source>priority must be 0, 1, 2 3,or 4</source>
+ <source>priority must be 0, 1, 2, 3, or 4</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -961,7 +961,7 @@ This transaction will unlock on block %llu, in approximately %s days (assuming 2
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="709"/>
- <source>sweep_all [mixin] address [payment_id] - Send all unlocked balance to an address</source>
+ <source>sweep_all [mixin] address [<payment_id>] - Send all unlocked balance to an address</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1124,7 +1124,7 @@ This transaction will unlock on block %llu, in approximately %s days (assuming 2
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="1887"/>
- <source>expected at least one payment_id</source>
+ <source>expected at least one payment ID</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1340,7 +1340,7 @@ Warning: Some input keys being spent are from </source>
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="706"/>
- <source>transfer [&lt;priority&gt;] [&lt;mixin_count&gt;] &lt;address&gt; &lt;amount&gt; [&lt;payment_id&gt;] - Transfer &lt;amount&gt; to &lt;address&gt;. &lt;priority&gt; is the priority of the transaction. The higher the priority, the higher the fee of the transaction. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command &quot;set priority&quot;) is used. &lt;mixin_count&gt; is the number of extra inputs to include for untraceability. Multiple payments can be made at once by adding &lt;address_2&gt; &lt;amount_2&gt; etcetera (before the payment ID, if it&apos;s included)</source>
+ <source>transfer [&lt;priority&gt;] [&lt;mixin_count&gt;] &lt;address&gt; &lt;amount&gt; [&lt;payment_id&gt;] - Transfer &lt;amount&gt; to &lt;address&gt;. &lt;priority&gt; is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command &quot;set priority&quot;) is used. &lt;mixin_count&gt; is the number of extra inputs to include for untraceability. Multiple payments can be made at once by adding &lt;address_2&gt; &lt;amount_2&gt; etcetera (before the payment ID, if it&apos;s included)</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -1612,7 +1612,7 @@ Warning: Some input keys being spent are from </source>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="1306"/>
<location filename="../src/simplewallet/simplewallet.cpp" line="1311"/>
- <source>invalid language choice passed. Please try again.
+ <source>invalid language choice entered. Please try again.
</source>
<translation type="unfinished"></translation>
</message>
@@ -2493,7 +2493,7 @@ Outputs per *: </source>
</message>
<message>
<location filename="../src/wallet/wallet2.cpp" line="460"/>
- <source>Enter new wallet password</source>
+ <source>Enter new password for the wallet</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -2651,13 +2651,13 @@ Outputs per *: </source>
<message>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1789"/>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1814"/>
- <source>Storing wallet...</source>
+ <source>Saving wallet...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1791"/>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1816"/>
- <source>Stored ok</source>
+ <source>Saved ok</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -2672,22 +2672,22 @@ Outputs per *: </source>
</message>
<message>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1805"/>
- <source>Failed to initialize wallet rpc server</source>
+ <source>Failed to initialize wallet RPC server</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1809"/>
- <source>Starting wallet rpc server</source>
+ <source>Starting wallet RPC server</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1811"/>
- <source>Stopped wallet rpc server</source>
+ <source>Stopped wallet RPC server</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1820"/>
- <source>Failed to store wallet: </source>
+ <source>Failed to save wallet: </source>
<translation type="unfinished"></translation>
</message>
</context>
diff --git a/translations/monero_fr.ts b/translations/monero_fr.ts
index 5cef15a92..c4e9a0f36 100644
--- a/translations/monero_fr.ts
+++ b/translations/monero_fr.ts
@@ -414,7 +414,7 @@
<name>cryptonote::rpc_args</name>
<message>
<location filename="../src/rpc/rpc_args.cpp" line="38"/>
- <source>Specify ip to bind rpc server</source>
+ <source>Specify IP to bind RPC server</source>
<translation>Spécifier l&apos;IP à laquelle lier le serveur RPC</translation>
</message>
<message>
@@ -527,8 +527,8 @@
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="710"/>
- <source>sweep_below &lt;amount_threshold&gt; [mixin] address [payment_id] - Send all unlocked outputs below the threshold to an address</source>
- <translation>sweep_below &lt;montant_seuil&gt; [mixin] adresse [ID_paiement] - Envoyer toutes les sorties débloquées sous le seuil vers une adresse</translation>
+ <source>sweep_below &lt;amount_threshold&gt; [mixin] address [<payment_id>] - Send all unlocked outputs below the threshold to an address</source>
+ <translation>sweep_below &lt;montant_seuil&gt; [mixin] adresse [<ID_paiement>] - Envoyer toutes les sorties débloquées sous le seuil vers une adresse</translation>
</message>
<message>
<source>Available options: seed language - set wallet seed language; always-confirm-transfers &lt;1|0&gt; - whether to confirm unsplit txes; print-ring-members &lt;1|0&gt; - whether to print detailed information about ring members during confirmation; store-tx-info &lt;1|0&gt; - whether to store outgoing tx info (destination address, payment ID, tx secret key) for future reference; default-mixin &lt;n&gt; - set default mixin (default is 4); auto-refresh &lt;1|0&gt; - whether to automatically sync new blocks from the daemon; refresh-type &lt;full|optimize-coinbase|no-coinbase|default&gt; - set wallet refresh behaviour; priority [0|1|2|3|4] - default/unimportant/normal/elevated/priority fee; confirm-missing-payment-id &lt;1|0&gt;; ask-password &lt;1|0&gt;; unit &lt;monero|millinero|micronero|nanonero|piconero&gt; - set default monero (sub-)unit; min-outputs-count [n] - try to keep at least that many outputs of value at least min-outputs-value; min-outputs-value [n] - try to keep at least min-outputs-count outputs of at least that value - merge-destinations &lt;1|0&gt; - whether to merge multiple payments to the same destination address</source>
@@ -872,7 +872,7 @@ Cette transaction sera déverrouillée au bloc %llu, dans approximativement %s j
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="2921"/>
- <source>missing amount threshold</source>
+ <source>missing threshold amount</source>
<translation>montant seuil manquant</translation>
</message>
<message>
@@ -917,7 +917,7 @@ Cette transaction sera déverrouillée au bloc %llu, dans approximativement %s j
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="3137"/>
- <source>daemon is busy. Please try later</source>
+ <source>daemon is busy. Please try again later</source>
<translation>le démon est occupé. Veuillez réessayer plus tard</translation>
</message>
<message>
@@ -952,12 +952,12 @@ Cette transaction sera déverrouillée au bloc %llu, dans approximativement %s j
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="525"/>
- <source>priority must be 0, 1, 2, 3,or 4</source>
+ <source>priority must be 0, 1, 2, 3, or 4</source>
<translation>la priorité doit être 0, 1, 2, 3 ou 4</translation>
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="540"/>
- <source>priority must be 0, 1, 2 3,or 4</source>
+ <source>priority must be 0, 1, 2, 3, or 4</source>
<translation>la priorité doit être 0, 1, 2, 3 ou 4</translation>
</message>
<message>
@@ -982,8 +982,8 @@ Cette transaction sera déverrouillée au bloc %llu, dans approximativement %s j
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="709"/>
- <source>sweep_all [mixin] address [payment_id] - Send all unlocked balance to an address</source>
- <translation>sweep_all [mixin] adresse [ID_paiement] - Envoyer tout le solde débloqué à une adresse</translation>
+ <source>sweep_all [mixin] address [<payment_id>] - Send all unlocked balance to an address</source>
+ <translation>sweep_all [mixin] adresse [<ID_paiement>] - Envoyer tout le solde débloqué à une adresse</translation>
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="711"/>
@@ -1149,7 +1149,7 @@ Cette transaction sera déverrouillée au bloc %llu, dans approximativement %s j
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="1887"/>
- <source>expected at least one payment_id</source>
+ <source>expected at least one payment ID</source>
<translation>au moins un ID de paiement attendu</translation>
</message>
<message>
@@ -1371,7 +1371,7 @@ Attention : Certaines clés d&apos;entrées étant dépensées sont issues de <
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="706"/>
- <source>transfer [&lt;priority&gt;] [&lt;mixin_count&gt;] &lt;address&gt; &lt;amount&gt; [&lt;payment_id&gt;] - Transfer &lt;amount&gt; to &lt;address&gt;. &lt;priority&gt; is the priority of the transaction. The higher the priority, the higher the fee of the transaction. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command &quot;set priority&quot;) is used. &lt;mixin_count&gt; is the number of extra inputs to include for untraceability. Multiple payments can be made at once by adding &lt;address_2&gt; &lt;amount_2&gt; etcetera (before the payment ID, if it&apos;s included)</source>
+ <source>transfer [&lt;priority&gt;] [&lt;mixin_count&gt;] &lt;address&gt; &lt;amount&gt; [&lt;payment_id&gt;] - Transfer &lt;amount&gt; to &lt;address&gt;. &lt;priority&gt; is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command &quot;set priority&quot;) is used. &lt;mixin_count&gt; is the number of extra inputs to include for untraceability. Multiple payments can be made at once by adding &lt;address_2&gt; &lt;amount_2&gt; etcetera (before the payment ID, if it&apos;s included)</source>
<translation>transfer [&lt;priorité&gt;] [&lt;mixin&gt;] &lt;adresse&gt; &lt;montant&gt; [&lt;ID_paiement&gt;] - Transférer &lt;montant&gt; à &lt;adresse&gt;. &lt;priorité&gt; est la priorité de la transaction. Plus la priorité est élevée, plues les frais de transaction seront élévés. Les valeurs de priorité valies sont dans l&apos;ordre (de la plus basse à la plus élevée) : unimportant, normal, elevated, priority. Si ce paramètre est omis, la valeur par défaut (voir la commande &quot;set priority&quot;) est utilisée. &lt;mixin&gt; est le nombre d&apos;entrées supplémentaires à inclure pour l&apos;intraçabilité. De multiples paiements peuvent être effectués d&apos;un coup en ajoutant &lt;adresse_2&gt; &lt;montant_2&gt; et cetera (avant l&apos;ID de paiement, s&apos;il est inclus)</translation>
</message>
<message>
@@ -1643,7 +1643,7 @@ Attention : Certaines clés d&apos;entrées étant dépensées sont issues de <
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="1306"/>
<location filename="../src/simplewallet/simplewallet.cpp" line="1311"/>
- <source>invalid language choice passed. Please try again.
+ <source>invalid language choice entered. Please try again.
</source>
<translation>choix de langue passé invalide. Veuillez réessayer.
</translation>
@@ -2543,7 +2543,7 @@ Sorties par * : </translation>
</message>
<message>
<location filename="../src/wallet/wallet2.cpp" line="460"/>
- <source>Enter new wallet password</source>
+ <source>Enter new password for the wallet</source>
<translation>Entrez le mot de passe du portefeuille</translation>
</message>
<message>
@@ -2701,14 +2701,14 @@ Sorties par * : </translation>
<message>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1789"/>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1814"/>
- <source>Storing wallet...</source>
+ <source>Saving wallet...</source>
<translation>Sauvegarde du portefeuille...</translation>
</message>
<message>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1791"/>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1816"/>
- <source>Stored ok</source>
- <translation>Sauvegarde OK</translation>
+ <source>Saved ok</source>
+ <translation>Sauvegarde réussie</translation>
</message>
<message>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1794"/>
@@ -2722,22 +2722,22 @@ Sorties par * : </translation>
</message>
<message>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1805"/>
- <source>Failed to initialize wallet rpc server</source>
+ <source>Failed to initialize wallet RPC server</source>
<translation>Échec de l&apos;initialisation du serveur RPC du portefeuille</translation>
</message>
<message>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1809"/>
- <source>Starting wallet rpc server</source>
+ <source>Starting wallet RPC server</source>
<translation>Démarrage du serveur RPC du portefeuille</translation>
</message>
<message>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1811"/>
- <source>Stopped wallet rpc server</source>
+ <source>Stopped wallet RPC server</source>
<translation>Arrêt du serveur RPC du portefeuille</translation>
</message>
<message>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1820"/>
- <source>Failed to store wallet: </source>
+ <source>Failed to save wallet: </source>
<translation>Échec de la sauvegarde du portefeuille : </translation>
</message>
</context>
diff --git a/translations/monero_it.ts b/translations/monero_it.ts
index 3674b2a32..d0cc40304 100644
--- a/translations/monero_it.ts
+++ b/translations/monero_it.ts
@@ -414,8 +414,8 @@
<name>cryptonote::rpc_args</name>
<message>
<location filename="../src/rpc/rpc_args.cpp" line="38"/>
- <source>Specify ip to bind rpc server</source>
- <translation>Specificare ip da associare al server rpc</translation>
+ <source>Specify IP to bind RPC server</source>
+ <translation>Specificare IP da associare al server RPC</translation>
</message>
<message>
<location filename="../src/rpc/rpc_args.cpp" line="39"/>
@@ -527,8 +527,8 @@
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="710"/>
- <source>sweep_below &lt;amount_threshold&gt; [mixin] address [payment_id] - Send all unlocked outputs below the threshold to an address</source>
- <translation>sweep_below &lt;amount_threshold&gt; [mixin] address [payment_id] - Invia tutti gli outputs sbloccati sotto la soglia specificata a un indirizzo</translation>
+ <source>sweep_below &lt;amount_threshold&gt; [mixin] address [<payment_id>] - Send all unlocked outputs below the threshold to an address</source>
+ <translation>sweep_below &lt;amount_threshold&gt; [mixin] address [<payment_id>] - Invia tutti gli outputs sbloccati sotto la soglia specificata a un indirizzo</translation>
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="727"/>
@@ -887,7 +887,7 @@ Questa transazione verrà sbloccata al blocco %llu, in approssimativamente %s gi
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="3137"/>
- <source>daemon is busy. Please try later</source>
+ <source>daemon is busy. Please try again later</source>
<translation>il daemon è occupato. Prova più tardi</translation>
</message>
<message>
@@ -922,13 +922,13 @@ Questa transazione verrà sbloccata al blocco %llu, in approssimativamente %s gi
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="525"/>
- <source>priority must be 0, 1, 2, 3,or 4</source>
- <translation>la priorità deve essere 0, 1, 2, 3,or 4</translation>
+ <source>priority must be 0, 1, 2, 3, or 4</source>
+ <translation>la priorità deve essere 0, 1, 2, 3, or 4</translation>
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="540"/>
- <source>priority must be 0, 1, 2 3,or 4</source>
- <translation>la priorità deve essere 0, 1, 2 3, or 4</translation>
+ <source>priority must be 0, 1, 2, 3, or 4</source>
+ <translation>la priorità deve essere 0, 1, 2, 3, or 4</translation>
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="623"/>
@@ -952,8 +952,8 @@ Questa transazione verrà sbloccata al blocco %llu, in approssimativamente %s gi
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="709"/>
- <source>sweep_all [mixin] address [payment_id] - Send all unlocked balance to an address</source>
- <translation>sweep_all [mixin] address [payment_id] - Manda tutto il bilancio sbloccato ad un indirizzo</translation>
+ <source>sweep_all [mixin] address [<payment_id>] - Send all unlocked balance to an address</source>
+ <translation>sweep_all [mixin] address [<payment_id>] - Manda tutto il bilancio sbloccato ad un indirizzo</translation>
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="711"/>
@@ -1115,8 +1115,8 @@ Questa transazione verrà sbloccata al blocco %llu, in approssimativamente %s gi
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="1887"/>
- <source>expected at least one payment_id</source>
- <translation>deve esserci almeno un payment_id</translation>
+ <source>expected at least one payment ID</source>
+ <translation>deve esserci almeno un payment ID</translation>
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="1896"/>
@@ -1336,7 +1336,7 @@ Avviso: alcune chiavi di input spese vengono da </translation>
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="706"/>
- <source>transfer [&lt;priority&gt;] [&lt;mixin_count&gt;] &lt;address&gt; &lt;amount&gt; [&lt;payment_id&gt;] - Transfer &lt;amount&gt; to &lt;address&gt;. &lt;priority&gt; is the priority of the transaction. The higher the priority, the higher the fee of the transaction. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command &quot;set priority&quot;) is used. &lt;mixin_count&gt; is the number of extra inputs to include for untraceability. Multiple payments can be made at once by adding &lt;address_2&gt; &lt;amount_2&gt; etcetera (before the payment ID, if it&apos;s included)</source>
+ <source>transfer [&lt;priority&gt;] [&lt;mixin_count&gt;] &lt;address&gt; &lt;amount&gt; [&lt;payment_id&gt;] - Transfer &lt;amount&gt; to &lt;address&gt;. &lt;priority&gt; is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command &quot;set priority&quot;) is used. &lt;mixin_count&gt; is the number of extra inputs to include for untraceability. Multiple payments can be made at once by adding &lt;address_2&gt; &lt;amount_2&gt; etcetera (before the payment ID, if it&apos;s included)</source>
<translation>transfer [&lt;priority&gt;] [&lt;mixin_count&gt;] &lt;address&gt; &lt;amount&gt; [&lt;payment_id&gt;] - Transfer &lt;amount&gt; to &lt;address&gt;. &lt;priority&gt; è la priorità della transazione. Maggiore è la priorità, maggiori saranno le tasse per la transazione. Valori validi in ordini di priorità (dal più basso al più alto) sono:unimportant, normal, elevated, priority. se omesso, verrà usato il valore standard (vedi il comando &quot;set priority&quot;). &lt;mixin_count&gt; è il numero di inputs extra da inludere per intracciabilità. Puoi eseguire pagamenti multipli in una volta aggiungendo &lt;address_2&gt; &lt;amount_2&gt; etcetera (prima dell&apos; ID pagamento, se incluso)</translation>
</message>
<message>
@@ -1608,7 +1608,7 @@ Avviso: alcune chiavi di input spese vengono da </translation>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="1306"/>
<location filename="../src/simplewallet/simplewallet.cpp" line="1311"/>
- <source>invalid language choice passed. Please try again.
+ <source>invalid language choice entered. Please try again.
</source>
<translation>linguaggio selezionato scorretto. Prova di nuovo.</translation>
</message>
@@ -1755,7 +1755,7 @@ di nuovo il tuo portafoglio (le chiavi del tuo portafoglio NON sono a rischio in
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="2921"/>
- <source>missing amount threshold</source>
+ <source>missing threshold amount</source>
<translation>manca la soglia massima dell&apos;ammontare</translation>
</message>
<message>
@@ -2512,7 +2512,7 @@ Outputs per *: </source>
</message>
<message>
<location filename="../src/wallet/wallet2.cpp" line="460"/>
- <source>Enter new wallet password</source>
+ <source>Enter new password for the wallet</source>
<translation>Inserisci una nuova password per il portafoglio</translation>
</message>
<message>
@@ -2670,13 +2670,13 @@ Outputs per *: </source>
<message>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1789"/>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1814"/>
- <source>Storing wallet...</source>
+ <source>Saving wallet...</source>
<translation>Sto salvando il portafoglio...</translation>
</message>
<message>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1791"/>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1816"/>
- <source>Stored ok</source>
+ <source>Saved ok</source>
<translation>Salvato con successo</translation>
</message>
<message>
@@ -2691,22 +2691,22 @@ Outputs per *: </source>
</message>
<message>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1805"/>
- <source>Failed to initialize wallet rpc server</source>
- <translation>Inizializzazione server rpc portafoglio fallita</translation>
+ <source>Failed to initialize wallet RPC server</source>
+ <translation>Inizializzazione server RPC portafoglio fallita</translation>
</message>
<message>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1809"/>
- <source>Starting wallet rpc server</source>
+ <source>Starting wallet RPC server</source>
<translation>Server RPC portafoglio in avvio</translation>
</message>
<message>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1811"/>
- <source>Stopped wallet rpc server</source>
+ <source>Stopped wallet RPC server</source>
<translation>Server RPC portafoglio arrestato</translation>
</message>
<message>
<location filename="../src/wallet/wallet_rpc_server.cpp" line="1820"/>
- <source>Failed to store wallet: </source>
+ <source>Failed to save wallet: </source>
<translation>Impossibile salvare portafoglio: </translation>
</message>
</context>
diff --git a/translations/monero_sv.ts b/translations/monero_sv.ts
index 0090857c0..7decd2f5a 100644
--- a/translations/monero_sv.ts
+++ b/translations/monero_sv.ts
@@ -2397,7 +2397,7 @@ Utgångar per *: </translation>
</message>
<message>
<location filename="../src/simplewallet/simplewallet.cpp" line="122"/>
- <source>Create non-deterministic view and spend keys</source>
+ <source>Generate non-deterministic view and spend keys</source>
<translation>Skapa non-deterministic visnings- och spendernyckel</translation>
</message>
<message>
@@ -2612,7 +2612,7 @@ Utgångar per *: </translation>
</message>
<message>
<location filename="../src/wallet/wallet2.cpp" line="356"/>
- <source>Cannot create deprecated wallets from JSON</source>
+ <source>Cannot generate deprecated wallets from JSON</source>
<translation>Det går inte att skapa inaktuella plånböcker från JSON</translation>
</message>
<message>