diff options
Diffstat (limited to 'src')
59 files changed, 665 insertions, 269 deletions
diff --git a/src/blockchain_utilities/blockchain_ancestry.cpp b/src/blockchain_utilities/blockchain_ancestry.cpp index b1b238427..99a84606d 100644 --- a/src/blockchain_utilities/blockchain_ancestry.cpp +++ b/src/blockchain_utilities/blockchain_ancestry.cpp @@ -32,6 +32,7 @@ #include <boost/algorithm/string.hpp> #include <boost/archive/portable_binary_iarchive.hpp> #include <boost/archive/portable_binary_oarchive.hpp> +#include <boost/filesystem/path.hpp> #include "common/unordered_containers_boost_serialization.h" #include "common/command_line.h" #include "common/varint.h" diff --git a/src/blockchain_utilities/blockchain_blackball.cpp b/src/blockchain_utilities/blockchain_blackball.cpp index e439895bf..18a37434c 100644 --- a/src/blockchain_utilities/blockchain_blackball.cpp +++ b/src/blockchain_utilities/blockchain_blackball.cpp @@ -28,6 +28,7 @@ #include <boost/range/adaptor/transformed.hpp> #include <boost/algorithm/string.hpp> +#include <boost/filesystem.hpp> #include "common/unordered_containers_boost_serialization.h" #include "common/command_line.h" #include "common/varint.h" diff --git a/src/blockchain_utilities/blockchain_depth.cpp b/src/blockchain_utilities/blockchain_depth.cpp index 6199586bf..8c3c3a009 100644 --- a/src/blockchain_utilities/blockchain_depth.cpp +++ b/src/blockchain_utilities/blockchain_depth.cpp @@ -27,6 +27,7 @@ // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <boost/range/adaptor/transformed.hpp> +#include <boost/filesystem/path.hpp> #include <boost/algorithm/string.hpp> #include "common/command_line.h" #include "common/varint.h" diff --git a/src/blockchain_utilities/blockchain_prune.cpp b/src/blockchain_utilities/blockchain_prune.cpp index 9a9d58c46..b1c599f3a 100644 --- a/src/blockchain_utilities/blockchain_prune.cpp +++ b/src/blockchain_utilities/blockchain_prune.cpp @@ -29,6 +29,8 @@ #include <array> #include <lmdb.h> #include <boost/algorithm/string.hpp> +#include <boost/system/error_code.hpp> +#include <boost/filesystem.hpp> #include "common/command_line.h" #include "common/pruning.h" #include "cryptonote_core/cryptonote_core.h" diff --git a/src/blockchain_utilities/blockchain_prune_known_spent_data.cpp b/src/blockchain_utilities/blockchain_prune_known_spent_data.cpp index 1a54778a7..78a662134 100644 --- a/src/blockchain_utilities/blockchain_prune_known_spent_data.cpp +++ b/src/blockchain_utilities/blockchain_prune_known_spent_data.cpp @@ -27,6 +27,7 @@ // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <boost/algorithm/string.hpp> +#include <boost/filesystem.hpp> #include "common/command_line.h" #include "serialization/crypto.h" #include "cryptonote_core/tx_pool.h" diff --git a/src/blockchain_utilities/blockchain_stats.cpp b/src/blockchain_utilities/blockchain_stats.cpp index 1f728b4e5..5f5ca6abf 100644 --- a/src/blockchain_utilities/blockchain_stats.cpp +++ b/src/blockchain_utilities/blockchain_stats.cpp @@ -27,6 +27,7 @@ // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <boost/algorithm/string.hpp> +#include <boost/filesystem.hpp> #include "common/command_line.h" #include "common/varint.h" #include "cryptonote_basic/cryptonote_boost_serialization.h" diff --git a/src/blockchain_utilities/blockchain_usage.cpp b/src/blockchain_utilities/blockchain_usage.cpp index 095e6c503..8356ef420 100644 --- a/src/blockchain_utilities/blockchain_usage.cpp +++ b/src/blockchain_utilities/blockchain_usage.cpp @@ -28,6 +28,7 @@ #include <boost/range/adaptor/transformed.hpp> #include <boost/algorithm/string.hpp> +#include <boost/filesystem/path.hpp> #include "common/command_line.h" #include "common/varint.h" #include "cryptonote_core/tx_pool.h" diff --git a/src/checkpoints/checkpoints.cpp b/src/checkpoints/checkpoints.cpp index c88a630cc..6b48d8723 100644 --- a/src/checkpoints/checkpoints.cpp +++ b/src/checkpoints/checkpoints.cpp @@ -34,6 +34,8 @@ #include "string_tools.h" #include "storages/portable_storage_template_helper.h" // epee json include #include "serialization/keyvalue_serialization.h" +#include <boost/system/error_code.hpp> +#include <boost/filesystem.hpp> #include <functional> #include <vector> diff --git a/src/common/dns_utils.cpp b/src/common/dns_utils.cpp index c31d1dd96..f0b617798 100644 --- a/src/common/dns_utils.cpp +++ b/src/common/dns_utils.cpp @@ -37,6 +37,7 @@ #include <boost/thread/mutex.hpp> #include <boost/algorithm/string/join.hpp> #include <boost/optional.hpp> +#include <boost/utility/string_ref.hpp> using namespace epee; #undef MONERO_DEFAULT_LOG_CATEGORY @@ -124,6 +125,7 @@ static const char *get_record_name(int record_type) case DNS_TYPE_A: return "A"; case DNS_TYPE_TXT: return "TXT"; case DNS_TYPE_AAAA: return "AAAA"; + case DNS_TYPE_TLSA: return "TLSA"; default: return "unknown"; } } @@ -186,6 +188,13 @@ boost::optional<std::string> txt_to_string(const char* src, size_t len) return std::string(src+1, len-1); } +boost::optional<std::string> tlsa_to_string(const char* src, size_t len) +{ + if (len < 4) + return boost::none; + return std::string(src, len); +} + // custom smart pointer. // TODO: see if std::auto_ptr and the like support custom destructors template<typename type, void (*freefunc)(type*)> @@ -326,11 +335,15 @@ std::vector<std::string> DNSResolver::get_record(const std::string& url, int rec // destructor takes care of cleanup ub_result_ptr result; + MDEBUG("Performing DNSSEC " << get_record_name(record_type) << " record query for " << url); + // call DNS resolver, blocking. if return value not zero, something went wrong if (!ub_resolve(m_data->m_ub_context, string_copy(url.c_str()), record_type, DNS_CLASS_IN, &result)) { dnssec_available = (result->secure || result->bogus); dnssec_valid = result->secure && !result->bogus; + if (dnssec_available && !dnssec_valid) + MWARNING("Invalid DNSSEC " << get_record_name(record_type) << " record signature for " << url << ": " << result->why_bogus); if (result->havedata) { for (size_t i=0; result->data[i] != NULL; i++) @@ -338,8 +351,9 @@ std::vector<std::string> DNSResolver::get_record(const std::string& url, int rec boost::optional<std::string> res = (*reader)(result->data[i], result->len[i]); if (res) { - MINFO("Found \"" << *res << "\" in " << get_record_name(record_type) << " record for " << url); - addresses.push_back(*res); + // do not dump dns record directly from dns into log + MINFO("Found " << get_record_name(record_type) << " record for " << url); + addresses.push_back(std::move(*res)); } } } @@ -363,6 +377,17 @@ std::vector<std::string> DNSResolver::get_txt_record(const std::string& url, boo return get_record(url, DNS_TYPE_TXT, txt_to_string, dnssec_available, dnssec_valid); } +std::vector<std::string> DNSResolver::get_tlsa_tcp_record(const boost::string_ref url, const boost::string_ref port, bool& dnssec_available, bool& dnssec_valid) +{ + std::string service_addr; + service_addr.reserve(url.size() + port.size() + 7); + service_addr.push_back('_'); + service_addr.append(port.data(), port.size()); + service_addr.append("._tcp."); + service_addr.append(url.data(), url.size()); + return get_record(service_addr, DNS_TYPE_TLSA, tlsa_to_string, dnssec_available, dnssec_valid); +} + std::string DNSResolver::get_dns_format_from_oa_address(const std::string& oa_addr) { std::string addr(oa_addr); diff --git a/src/common/dns_utils.h b/src/common/dns_utils.h index 30c4cced2..99e91bc54 100644 --- a/src/common/dns_utils.h +++ b/src/common/dns_utils.h @@ -31,15 +31,17 @@ #include <string> #include <functional> #include <boost/optional/optional_fwd.hpp> +#include <boost/utility/string_ref_fwd.hpp> namespace tools { // RFC defines for record types and classes for DNS, gleaned from ldns source -const static int DNS_CLASS_IN = 1; -const static int DNS_TYPE_A = 1; -const static int DNS_TYPE_TXT = 16; -const static int DNS_TYPE_AAAA = 8; +constexpr const int DNS_CLASS_IN = 1; +constexpr const int DNS_TYPE_A = 1; +constexpr const int DNS_TYPE_TXT = 16; +constexpr const int DNS_TYPE_AAAA = 8; +constexpr const int DNS_TYPE_TLSA = 52; struct DNSResolverData; @@ -106,6 +108,17 @@ public: std::vector<std::string> get_txt_record(const std::string& url, bool& dnssec_available, bool& dnssec_valid); /** + * @brief gets all TLSA TCP records from a DNS query for the supplied URL; + * if no TLSA record present returns an empty vector. + * + * @param url A string containing a URL to query for + * @param port The service port number (as string) to query + * + * @return A vector of strings containing all TLSA records; or an empty vector + */ + std::vector<std::string> get_tlsa_tcp_record(boost::string_ref url, boost::string_ref port, bool& dnssec_available, bool& dnssec_valid); + + /** * @brief Gets a DNS address from OpenAlias format * * If the address looks good, but contains one @ symbol, replace that with a . diff --git a/src/common/i18n.cpp b/src/common/i18n.cpp index ebc367b3a..051220ee1 100644 --- a/src/common/i18n.cpp +++ b/src/common/i18n.cpp @@ -35,6 +35,10 @@ #include "common/i18n.h" #include "translation_files.h" +#include <boost/system/error_code.hpp> +#include <boost/filesystem.hpp> +#include <algorithm> + #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "i18n" diff --git a/src/crypto/rx-slow-hash.c b/src/crypto/rx-slow-hash.c index fa35a32e2..801987e37 100644 --- a/src/crypto/rx-slow-hash.c +++ b/src/crypto/rx-slow-hash.c @@ -264,12 +264,14 @@ void rx_slow_hash(const uint64_t mainheight, const uint64_t seedheight, const ch cache = rx_sp->rs_cache; if (cache == NULL) { - if (cache == NULL) { + if (!(disabled_flags() & RANDOMX_FLAG_LARGE_PAGES)) { cache = randomx_alloc_cache(flags | RANDOMX_FLAG_LARGE_PAGES); if (cache == NULL) { mdebug(RX_LOGCAT, "Couldn't use largePages for RandomX cache"); - cache = randomx_alloc_cache(flags); } + } + if (cache == NULL) { + cache = randomx_alloc_cache(flags); if (cache == NULL) local_abort("Couldn't allocate RandomX cache"); } @@ -291,11 +293,14 @@ void rx_slow_hash(const uint64_t mainheight, const uint64_t seedheight, const ch CTHR_MUTEX_LOCK(rx_dataset_mutex); if (!rx_dataset_nomem) { if (rx_dataset == NULL) { - rx_dataset = randomx_alloc_dataset(RANDOMX_FLAG_LARGE_PAGES); - if (rx_dataset == NULL) { - mdebug(RX_LOGCAT, "Couldn't use largePages for RandomX dataset"); - rx_dataset = randomx_alloc_dataset(RANDOMX_FLAG_DEFAULT); + if (!(disabled_flags() & RANDOMX_FLAG_LARGE_PAGES)) { + rx_dataset = randomx_alloc_dataset(RANDOMX_FLAG_LARGE_PAGES); + if (rx_dataset == NULL) { + mdebug(RX_LOGCAT, "Couldn't use largePages for RandomX dataset"); + } } + if (rx_dataset == NULL) + rx_dataset = randomx_alloc_dataset(RANDOMX_FLAG_DEFAULT); if (rx_dataset != NULL) rx_initdata(rx_sp->rs_cache, miners, seedheight); } @@ -311,11 +316,14 @@ void rx_slow_hash(const uint64_t mainheight, const uint64_t seedheight, const ch } CTHR_MUTEX_UNLOCK(rx_dataset_mutex); } - rx_vm = randomx_create_vm(flags | RANDOMX_FLAG_LARGE_PAGES, rx_sp->rs_cache, rx_dataset); - if(rx_vm == NULL) { //large pages failed - mdebug(RX_LOGCAT, "Couldn't use largePages for RandomX VM"); - rx_vm = randomx_create_vm(flags, rx_sp->rs_cache, rx_dataset); + if (!(disabled_flags() & RANDOMX_FLAG_LARGE_PAGES)) { + rx_vm = randomx_create_vm(flags | RANDOMX_FLAG_LARGE_PAGES, rx_sp->rs_cache, rx_dataset); + if(rx_vm == NULL) { //large pages failed + mdebug(RX_LOGCAT, "Couldn't use largePages for RandomX VM"); + } } + if (rx_vm == NULL) + rx_vm = randomx_create_vm(flags, rx_sp->rs_cache, rx_dataset); if(rx_vm == NULL) {//fallback if everything fails flags = RANDOMX_FLAG_DEFAULT | (miners ? RANDOMX_FLAG_FULL_MEM : 0); rx_vm = randomx_create_vm(flags, rx_sp->rs_cache, rx_dataset); diff --git a/src/cryptonote_basic/connection_context.h b/src/cryptonote_basic/connection_context.h index a7d688300..ee26a0c07 100644 --- a/src/cryptonote_basic/connection_context.h +++ b/src/cryptonote_basic/connection_context.h @@ -77,6 +77,8 @@ namespace cryptonote int m_expect_response; uint64_t m_expect_height; size_t m_num_requested; + epee::copyable_atomic m_new_stripe_notification{0}; + epee::copyable_atomic m_idle_peer_notification{0}; }; inline std::string get_protocol_state_string(cryptonote_connection_context::state s) diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index 29f6dce5a..ae514aac6 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -44,6 +44,7 @@ #include "string_tools.h" #include "storages/portable_storage_template_helper.h" #include "boost/logic/tribool.hpp" +#include <boost/filesystem.hpp> #ifdef __APPLE__ #include <sys/times.h> diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index cdad39a2c..a3d695b85 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -57,6 +57,7 @@ #include "common/notify.h" #include "common/varint.h" #include "common/pruning.h" +#include "time_helper.h" #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "blockchain" diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 57104fd59..beae55b35 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -57,6 +57,8 @@ using namespace epee; #include "hardforks/hardforks.h" #include "version.h" +#include <boost/filesystem.hpp> + #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "cn" diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h index dbdf409b5..73cdd31cd 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.h +++ b/src/cryptonote_core/cryptonote_tx_utils.h @@ -44,10 +44,10 @@ namespace cryptonote typedef std::pair<uint64_t, rct::ctkey> output_entry; std::vector<output_entry> outputs; //index + key + optional ringct commitment - size_t real_output; //index in outputs vector of real output_entry + uint64_t real_output; //index in outputs vector of real output_entry crypto::public_key real_out_tx_key; //incoming real tx public key std::vector<crypto::public_key> real_out_additional_tx_keys; //incoming real tx additional public keys - size_t real_output_in_tx_index; //index in transaction outputs vector + uint64_t real_output_in_tx_index; //index in transaction outputs vector uint64_t amount; //money bool rct; //true if the output is rct rct::key mask; //ringct amount mask diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h index 28530f3e7..80dd2bc39 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.h +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h @@ -46,6 +46,8 @@ #include "block_queue.h" #include "common/perf_timer.h" #include "cryptonote_basic/connection_context.h" +#include "net/levin_base.h" +#include "p2p/net_node_common.h" #include <boost/circular_buffer.hpp> PUSH_WARNINGS @@ -195,10 +197,11 @@ namespace cryptonote bool post_notify(typename t_parameter::request& arg, cryptonote_connection_context& context) { LOG_PRINT_L2("[" << epee::net_utils::print_connection_context_short(context) << "] post " << typeid(t_parameter).name() << " -->"); - epee::byte_slice blob; - epee::serialization::store_t_to_binary(arg, blob, 256 * 1024); // optimize for block responses + + epee::levin::message_writer out{256 * 1024}; // optimize for block responses + epee::serialization::store_t_to_binary(arg, out.buffer); //handler_response_blocks_now(blob.size()); // XXX - return m_p2p->invoke_notify_to_peer(t_parameter::ID, epee::to_span(blob), context); + return m_p2p->invoke_notify_to_peer(t_parameter::ID, std::move(out), context); } }; diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index c798dbcdb..afc81f552 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -137,6 +137,41 @@ namespace cryptonote CHECK_AND_ASSERT_MES_CC( context.m_callback_request_count > 0, false, "false callback fired, but context.m_callback_request_count=" << context.m_callback_request_count); --context.m_callback_request_count; + uint32_t notified = true; + if (context.m_idle_peer_notification.compare_exchange_strong(notified, not notified)) + { + if (context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time != boost::date_time::not_a_date_time) + { + const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time(); + const boost::posix_time::time_duration dt = now - context.m_last_request_time; + const auto ms = dt.total_microseconds(); + if (ms > IDLE_PEER_KICK_TIME || (context.m_expect_response && ms > NON_RESPONSIVE_PEER_KICK_TIME)) + { + if (context.m_score-- >= 0) + { + MINFO(context << " kicking idle peer, last update " << (dt.total_microseconds() / 1.e6) << " seconds ago, expecting " << (int)context.m_expect_response); + context.m_last_request_time = boost::date_time::not_a_date_time; + context.m_expect_response = 0; + context.m_expect_height = 0; + context.m_state = cryptonote_connection_context::state_standby; // we'll go back to adding, then (if we can't), download + } + else + { + MINFO(context << "dropping idle peer with negative score"); + drop_connection_with_score(context, context.m_expect_response == 0 ? 1 : 5, false); + return false; + } + } + } + } + + notified = true; + if (context.m_new_stripe_notification.compare_exchange_strong(notified, not notified)) + { + if (context.m_state == cryptonote_connection_context::state_normal) + context.m_state = cryptonote_connection_context::state_synchronizing; + } + if(context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time == boost::posix_time::not_a_date_time) { NOTIFY_REQUEST_CHAIN::request r = {}; @@ -1687,7 +1722,7 @@ skip: const uint32_t peer_stripe = tools::get_pruning_stripe(context.m_pruning_seed); if (stripe && peer_stripe && peer_stripe != stripe) return true; - context.m_state = cryptonote_connection_context::state_synchronizing; + context.m_new_stripe_notification = true; LOG_PRINT_CCONTEXT_L2("requesting callback"); ++context.m_callback_request_count; m_p2p->request_callback(context); @@ -1710,7 +1745,6 @@ skip: bool t_cryptonote_protocol_handler<t_core>::kick_idle_peers() { MTRACE("Checking for idle peers..."); - std::vector<std::pair<boost::uuids::uuid, unsigned>> idle_peers; m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool { if (context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time != boost::date_time::not_a_date_time) @@ -1720,36 +1754,16 @@ skip: const auto ms = dt.total_microseconds(); if (ms > IDLE_PEER_KICK_TIME || (context.m_expect_response && ms > NON_RESPONSIVE_PEER_KICK_TIME)) { - if (context.m_score-- >= 0) - { - MINFO(context << " kicking idle peer, last update " << (dt.total_microseconds() / 1.e6) << " seconds ago, expecting " << (int)context.m_expect_response); - LOG_PRINT_CCONTEXT_L2("requesting callback"); - context.m_last_request_time = boost::date_time::not_a_date_time; - context.m_expect_response = 0; - context.m_expect_height = 0; - context.m_state = cryptonote_connection_context::state_standby; // we'll go back to adding, then (if we can't), download - ++context.m_callback_request_count; - m_p2p->request_callback(context); - } - else - { - idle_peers.push_back(std::make_pair(context.m_connection_id, context.m_expect_response == 0 ? 1 : 5)); - } + context.m_idle_peer_notification = true; + LOG_PRINT_CCONTEXT_L2("requesting callback"); + ++context.m_callback_request_count; + m_p2p->request_callback(context); + MLOG_PEER_STATE("requesting callback"); } } return true; }); - for (const auto &e: idle_peers) - { - const auto &uuid = e.first; - m_p2p->for_connection(uuid, [&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t f)->bool{ - MINFO(ctx << "dropping idle peer with negative score"); - drop_connection_with_score(ctx, e.second, false); - return true; - }); - } - return true; } //------------------------------------------------------------------------------------------------------------------------ @@ -2699,15 +2713,15 @@ skip: // send fluffy ones first, we want to encourage people to run that if (!fluffyConnections.empty()) { - epee::byte_slice fluffyBlob; - epee::serialization::store_t_to_binary(fluffy_arg, fluffyBlob, 32 * 1024); - m_p2p->relay_notify_to_list(NOTIFY_NEW_FLUFFY_BLOCK::ID, epee::to_span(fluffyBlob), std::move(fluffyConnections)); + epee::levin::message_writer fluffyBlob{32 * 1024}; + epee::serialization::store_t_to_binary(fluffy_arg, fluffyBlob.buffer); + m_p2p->relay_notify_to_list(NOTIFY_NEW_FLUFFY_BLOCK::ID, std::move(fluffyBlob), std::move(fluffyConnections)); } if (!fullConnections.empty()) { - epee::byte_slice fullBlob; - epee::serialization::store_t_to_binary(arg, fullBlob, 128 * 1024); - m_p2p->relay_notify_to_list(NOTIFY_NEW_BLOCK::ID, epee::to_span(fullBlob), std::move(fullConnections)); + epee::levin::message_writer fullBlob{128 * 1024}; + epee::serialization::store_t_to_binary(arg, fullBlob.buffer); + m_p2p->relay_notify_to_list(NOTIFY_NEW_BLOCK::ID, std::move(fullBlob), std::move(fullConnections)); } return true; @@ -2840,15 +2854,12 @@ skip: epee::string_tools::to_string_hex(context.m_pruning_seed) << "), score " << score << ", flush_all_spans " << flush_all_spans); - m_block_queue.flush_spans(context.m_connection_id, flush_all_spans); + if (score > 0) + m_p2p->add_host_fail(context.m_remote_address, score); - // copy since dropping the connection will invalidate the context, and thus the address - const auto remote_address = context.m_remote_address; + m_block_queue.flush_spans(context.m_connection_id, flush_all_spans); m_p2p->drop_connection(context); - - if (score > 0) - m_p2p->add_host_fail(remote_address, score); } //------------------------------------------------------------------------------------------------------------------------ template<class t_core> diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler_common.h b/src/cryptonote_protocol/cryptonote_protocol_handler_common.h index 79c2edf1d..57b1d049c 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler_common.h +++ b/src/cryptonote_protocol/cryptonote_protocol_handler_common.h @@ -30,8 +30,8 @@ #pragma once -#include "p2p/net_node_common.h" #include "cryptonote_protocol/cryptonote_protocol_defs.h" +#include "cryptonote_protocol/enums.h" #include "cryptonote_basic/connection_context.h" namespace cryptonote { diff --git a/src/cryptonote_protocol/levin_notify.cpp b/src/cryptonote_protocol/levin_notify.cpp index 1e9f3e399..0b065c3c3 100644 --- a/src/cryptonote_protocol/levin_notify.cpp +++ b/src/cryptonote_protocol/levin_notify.cpp @@ -159,7 +159,7 @@ namespace levin return get_out_connections(p2p, get_blockchain_height(p2p, core)); } - epee::byte_slice make_tx_payload(std::vector<blobdata>&& txs, const bool pad, const bool fluff) + epee::levin::message_writer make_tx_message(std::vector<blobdata>&& txs, const bool pad, const bool fluff) { NOTIFY_NEW_TRANSACTIONS::request request{}; request.txs = std::move(txs); @@ -193,21 +193,17 @@ namespace levin // if the size of _ moved enough, we might lose byte in size encoding, we don't care } - epee::byte_slice fullBlob; - if (!epee::serialization::store_t_to_binary(request, fullBlob)) + epee::levin::message_writer out; + if (!epee::serialization::store_t_to_binary(request, out.buffer)) throw std::runtime_error{"Failed to serialize to epee binary format"}; - return fullBlob; + return out; } bool make_payload_send_txs(connections& p2p, std::vector<blobdata>&& txs, const boost::uuids::uuid& destination, const bool pad, const bool fluff) { - const epee::byte_slice blob = make_tx_payload(std::move(txs), pad, fluff); - p2p.for_connection(destination, [&blob](detail::p2p_context& context) { - on_levin_traffic(context, true, true, false, blob.size(), NOTIFY_NEW_TRANSACTIONS::ID); - return true; - }); - return p2p.notify(NOTIFY_NEW_TRANSACTIONS::ID, epee::to_span(blob), destination); + epee::byte_slice blob = make_tx_message(std::move(txs), pad, fluff).finalize_notify(NOTIFY_NEW_TRANSACTIONS::ID); + return p2p.send(std::move(blob), destination); } /* The current design uses `asio::strand`s. The documentation isn't as clear @@ -653,10 +649,6 @@ namespace levin else message = zone_->noise.clone(); - zone_->p2p->for_connection(channel.connection, [&](detail::p2p_context& context) { - on_levin_traffic(context, true, true, false, message.size(), "noise"); - return true; - }); if (zone_->p2p->send(std::move(message), channel.connection)) { if (!channel.queue.empty() && channel.active.empty()) @@ -816,9 +808,8 @@ namespace levin // Padding is not useful when using noise mode. Send as stem so receiver // forwards in Dandelion++ mode. - const epee::byte_slice payload = make_tx_payload(std::move(txs), false, false); epee::byte_slice message = epee::levin::make_fragmented_notify( - zone_->noise, NOTIFY_NEW_TRANSACTIONS::ID, epee::to_span(payload) + zone_->noise.size(), NOTIFY_NEW_TRANSACTIONS::ID, make_tx_message(std::move(txs), false, false) ); if (CRYPTONOTE_MAX_FRAGMENTS * zone_->noise.size() < message.size()) { diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp index 5a7560874..abca614cc 100644 --- a/src/daemon/command_parser_executor.cpp +++ b/src/daemon/command_parser_executor.cpp @@ -30,6 +30,7 @@ #include "common/command_line.h" #include "net/parse.h" #include "daemon/command_parser_executor.h" +#include <boost/filesystem.hpp> #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "daemon" @@ -986,17 +987,67 @@ bool t_command_parser_executor::check_blockchain_pruning(const std::vector<std:: bool t_command_parser_executor::set_bootstrap_daemon(const std::vector<std::string>& args) { - const size_t args_count = args.size(); - if (args_count < 1 || args_count > 3) + struct parsed_t + { + std::string address; + std::string user; + std::string password; + std::string proxy; + }; + + boost::optional<parsed_t> parsed = [&args]() -> boost::optional<parsed_t> { + const size_t args_count = args.size(); + if (args_count == 0) + { + return {}; + } + if (args[0] == "auto") + { + if (args_count == 1) + { + return {{args[0], "", "", ""}}; + } + if (args_count == 2) + { + return {{args[0], "", "", args[1]}}; + } + } + else if (args[0] == "none") + { + if (args_count == 1) + { + return {{"", "", "", ""}}; + } + } + else + { + if (args_count == 1) + { + return {{args[0], "", "", ""}}; + } + if (args_count == 2) + { + return {{args[0], "", "", args[1]}}; + } + if (args_count == 3) + { + return {{args[0], args[1], args[2], ""}}; + } + if (args_count == 4) + { + return {{args[0], args[1], args[2], args[3]}}; + } + } + return {}; + }(); + + if (!parsed) { std::cout << "Invalid syntax: Wrong number of parameters. For more details, use the help command." << std::endl; return true; } - return m_executor.set_bootstrap_daemon( - args[0] != "none" ? args[0] : std::string(), - args_count > 1 ? args[1] : std::string(), - args_count > 2 ? args[2] : std::string()); + return m_executor.set_bootstrap_daemon(parsed->address, parsed->user, parsed->password, parsed->proxy); } bool t_command_parser_executor::flush_cache(const std::vector<std::string>& args) diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp index 4768bb842..63f44c4cd 100644 --- a/src/daemon/command_server.cpp +++ b/src/daemon/command_server.cpp @@ -326,7 +326,7 @@ t_command_server::t_command_server( m_command_lookup.set_handler( "set_bootstrap_daemon" , std::bind(&t_command_parser_executor::set_bootstrap_daemon, &m_parser, p::_1) - , "set_bootstrap_daemon (auto | none | host[:port] [username] [password])" + , "set_bootstrap_daemon (auto | none | host[:port] [username] [password]) [proxy_ip:proxy_port]" , "URL of a 'bootstrap' remote daemon that the connected wallets can use while this daemon is still not fully synced.\n" "Use 'auto' to enable automatic public nodes discovering and bootstrap daemon switching" ); diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index 8194fe642..16e6a304c 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -2405,7 +2405,8 @@ bool t_rpc_command_executor::check_blockchain_pruning() bool t_rpc_command_executor::set_bootstrap_daemon( const std::string &address, const std::string &username, - const std::string &password) + const std::string &password, + const std::string &proxy) { cryptonote::COMMAND_RPC_SET_BOOTSTRAP_DAEMON::request req; cryptonote::COMMAND_RPC_SET_BOOTSTRAP_DAEMON::response res; @@ -2414,6 +2415,7 @@ bool t_rpc_command_executor::set_bootstrap_daemon( req.address = address; req.username = username; req.password = password; + req.proxy = proxy; if (m_is_rpc) { diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h index 6fb5d6903..118f04731 100644 --- a/src/daemon/rpc_command_executor.h +++ b/src/daemon/rpc_command_executor.h @@ -168,7 +168,8 @@ public: bool set_bootstrap_daemon( const std::string &address, const std::string &username, - const std::string &password); + const std::string &password, + const std::string &proxy); bool rpc_payments(); diff --git a/src/mnemonics/electrum-words.cpp b/src/mnemonics/electrum-words.cpp index b6bc22a3d..8c79a53ca 100644 --- a/src/mnemonics/electrum-words.cpp +++ b/src/mnemonics/electrum-words.cpp @@ -491,6 +491,14 @@ namespace crypto return "<language not found>"; } + bool is_valid_language(const std::string &language) + { + const std::vector<const Language::Base*> language_instances = get_language_list(); + for (std::vector<const Language::Base*>::const_iterator it = language_instances.begin(); it != language_instances.end(); it++) + if ((*it)->get_english_language_name() == language || (*it)->get_language_name() == language) + return true; + return false; + } } } diff --git a/src/mnemonics/electrum-words.h b/src/mnemonics/electrum-words.h index 8d4c5be66..eb0c99e0b 100644 --- a/src/mnemonics/electrum-words.h +++ b/src/mnemonics/electrum-words.h @@ -124,6 +124,8 @@ namespace crypto * \return the name of the language in English */ std::string get_english_name_for(const std::string &name); + + bool is_valid_language(const std::string &language); } } diff --git a/src/net/CMakeLists.txt b/src/net/CMakeLists.txt index afcd42ef7..e93e27bcd 100644 --- a/src/net/CMakeLists.txt +++ b/src/net/CMakeLists.txt @@ -26,10 +26,10 @@ # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -set(net_sources dandelionpp.cpp error.cpp http.cpp i2p_address.cpp parse.cpp socks.cpp - socks_connect.cpp tor_address.cpp zmq.cpp) -set(net_headers dandelionpp.h error.h http.cpp i2p_address.h parse.h socks.h socks_connect.h - tor_address.h zmq.h) +set(net_sources dandelionpp.cpp error.cpp http.cpp i2p_address.cpp parse.cpp resolve.cpp + socks.cpp socks_connect.cpp tor_address.cpp zmq.cpp) +set(net_headers dandelionpp.h error.h http.cpp i2p_address.h parse.h socks.h resolve.h + socks_connect.h tor_address.h zmq.h) monero_add_library(net ${net_sources} ${net_headers}) target_link_libraries(net common epee ${ZMQ_LIB} ${Boost_ASIO_LIBRARY}) diff --git a/src/net/error.cpp b/src/net/error.cpp index 037f44d52..d2e713bc5 100644 --- a/src/net/error.cpp +++ b/src/net/error.cpp @@ -47,12 +47,18 @@ namespace { switch (net::error(value)) { + case net::error::bogus_dnssec: + return "Invalid response signature from DNSSEC enabled domain"; + case net::error::dns_query_failure: + return "Failed to retrieve desired DNS record"; case net::error::expected_tld: return "Expected top-level domain"; case net::error::invalid_host: return "Host value is not valid"; case net::error::invalid_i2p_address: return "Invalid I2P address"; + case net::error::invalid_mask: + return "CIDR netmask outside of 0-32 range"; case net::error::invalid_port: return "Invalid port value (expected 0-65535)"; case net::error::invalid_tor_address: @@ -71,6 +77,7 @@ namespace switch (net::error(value)) { case net::error::invalid_port: + case net::error::invalid_mask: return std::errc::result_out_of_range; case net::error::expected_tld: case net::error::invalid_tor_address: diff --git a/src/net/error.h b/src/net/error.h index 7c852dd20..746eb0ecb 100644 --- a/src/net/error.h +++ b/src/net/error.h @@ -37,13 +37,16 @@ namespace net enum class error : int { // 0 reserved for success (as per expect<T>) - expected_tld = 1, //!< Expected a tld + bogus_dnssec = 1, //!< Invalid response signature from DNSSEC enabled domain + dns_query_failure, //!< Failed to retrieve desired DNS record + expected_tld, //!< Expected a tld invalid_host, //!< Hostname is not valid invalid_i2p_address, + invalid_mask, //!< Outside of 0-32 range invalid_port, //!< Outside of 0-65535 range invalid_tor_address,//!< Invalid base32 or length unsupported_address,//!< Type not supported by `get_network_address` - invalid_mask, //!< Outside of 0-32 range + }; //! \return `std::error_category` for `net` namespace. diff --git a/src/net/resolve.cpp b/src/net/resolve.cpp new file mode 100644 index 000000000..1b43cf6c4 --- /dev/null +++ b/src/net/resolve.cpp @@ -0,0 +1,71 @@ +// Copyright (c) 2020, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "net/resolve.h" + +#include <boost/utility/string_ref.hpp> +#include "common/dns_utils.h" +#include "common/expect.h" +#include "net/error.h" + +namespace net +{ +namespace dnssec +{ + expect<service_response> resolve_hostname(const std::string& addr, const std::string& tlsa_port) + { + // use basic (blocking) unbound for now, possibly refactor later + tools::DNSResolver& resolver = tools::DNSResolver::instance(); + + bool dnssec_available = false; + bool dnssec_valid = false; + std::vector<std::string> ip_records = resolver.get_ipv4(addr, dnssec_available, dnssec_valid); + + if (dnssec_available && !dnssec_valid) + return {net::error::bogus_dnssec}; + + if (ip_records.empty()) + { + ip_records = resolver.get_ipv6(addr, dnssec_available, dnssec_valid); + if (dnssec_available && !dnssec_valid) + return {net::error::bogus_dnssec}; + if (ip_records.empty()) + return {net::error::dns_query_failure}; + } + + std::vector<std::string> tlsa{}; + if (dnssec_available && !tlsa_port.empty()) + { + tlsa = resolver.get_tlsa_tcp_record(addr, tlsa_port, dnssec_available, dnssec_valid); + if (!dnssec_valid) + return {net::error::bogus_dnssec}; + } + return {{std::move(ip_records), std::move(tlsa)}}; + } +} // dnssec +} // net diff --git a/src/net/resolve.h b/src/net/resolve.h new file mode 100644 index 000000000..46bd8e617 --- /dev/null +++ b/src/net/resolve.h @@ -0,0 +1,47 @@ +// Copyright (c) 2020, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <string> +#include <vector> + +template<typename> class expect; + +namespace net +{ +namespace dnssec +{ + struct service_response + { + std::vector<std::string> ip; //!< IPv4/6 records in dotted or semicolon notation + std::vector<std::string> tlsa; //!< DANE/TLSA records + }; + + //! \return IP + (optionally) DANE/TLSA records, failing if DNSSEC signature is "bogus" + expect<service_response> resolve_hostname(const std::string& addr, const std::string& tlsa_port = {}); +} // dnssec +} // net diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index db931122e..f2888674b 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -344,10 +344,9 @@ namespace nodetool virtual void on_connection_close(p2p_connection_context& context); virtual void callback(p2p_connection_context& context); //----------------- i_p2p_endpoint ------------------------------------------------------------- - virtual bool relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> connections); + virtual bool relay_notify_to_list(int command, epee::levin::message_writer message, std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> connections) final; virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::relay_method tx_relay); - virtual bool invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context); - virtual bool invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context); + virtual bool invoke_notify_to_peer(int command, epee::levin::message_writer message, const epee::net_utils::connection_context_base& context) final; virtual bool drop_connection(const epee::net_utils::connection_context_base& context); virtual void request_callback(const epee::net_utils::connection_context_base& context); virtual void for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&, peerid_type, uint32_t)> f); diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 07b45b9bd..e1d6d1e10 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -1203,9 +1203,8 @@ namespace nodetool if(!handle_remote_peerlist(rsp.local_peerlist_new, context)) { LOG_WARNING_CC(context, "COMMAND_TIMED_SYNC: failed to handle_remote_peerlist(...), closing connection."); - const auto remote_address = context.m_remote_address; m_network_zones.at(context.m_remote_address.get_zone()).m_net_server.get_config_object().close(context.m_connection_id ); - add_host_fail(remote_address); + add_host_fail(context.m_remote_address); } if(!context.m_is_income) m_network_zones.at(context.m_remote_address.get_zone()).m_peerlist.set_peer_just_seen(context.peer_id, context.m_remote_address, context.m_pruning_seed, context.m_rpc_port, context.m_rpc_credits_per_hash); @@ -1230,8 +1229,8 @@ namespace nodetool if(!max_index) return 0; - size_t x = crypto::rand<size_t>()%(max_index+1); - size_t res = (x*x*x)/(max_index*max_index); //parabola \/ + size_t x = crypto::rand<size_t>()%(16*max_index+1); + size_t res = (x*x*x)/(max_index*max_index*16*16*16); //parabola \/ MDEBUG("Random connection index=" << res << "(x="<< x << ", max_index=" << max_index << ")"); return res; } @@ -1369,7 +1368,7 @@ namespace nodetool if(just_take_peerlist) { zone.m_net_server.get_config_object().close(con->m_connection_id); - MDEBUG(na.str() << "CONNECTION HANDSHAKED OK AND CLOSED."); + LOG_DEBUG_CC(*con, "CONNECTION HANDSHAKED OK AND CLOSED."); return true; } @@ -1431,7 +1430,7 @@ namespace nodetool zone.m_net_server.get_config_object().close(con->m_connection_id); - MDEBUG(na.str() << "CONNECTION HANDSHAKED OK AND CLOSED."); + LOG_DEBUG_CC(*con, "CONNECTION HANDSHAKED OK AND CLOSED."); return true; } @@ -2003,15 +2002,22 @@ namespace nodetool { if (ip.empty()) continue; + auto subnet = net::get_ipv4_subnet_address(ip); + if (subnet) + { + block_subnet(*subnet, DNS_BLOCKLIST_LIFETIME); + ++good; + continue; + } const expect<epee::net_utils::network_address> parsed_addr = net::get_network_address(ip, 0); - if (!parsed_addr) + if (parsed_addr) { - MWARNING("Invalid IP address from DNS blocklist: " << ip << " - " << parsed_addr.error()); - ++bad; + block_host(*parsed_addr, DNS_BLOCKLIST_LIFETIME, true); + ++good; continue; } - block_host(*parsed_addr, DNS_BLOCKLIST_LIFETIME, true); - ++good; + MWARNING("Invalid IP address or subnet from DNS blocklist: " << ip << " - " << parsed_addr.error()); + ++bad; } } if (good > 0) @@ -2169,8 +2175,9 @@ namespace nodetool } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> - bool node_server<t_payload_net_handler>::relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> connections) + bool node_server<t_payload_net_handler>::relay_notify_to_list(int command, epee::levin::message_writer data_buff, std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> connections) { + epee::byte_slice message = data_buff.finalize_notify(command); std::sort(connections.begin(), connections.end()); auto zone = m_network_zones.begin(); for(const auto& c_id: connections) @@ -2188,7 +2195,7 @@ namespace nodetool ++zone; } if (zone->first == c_id.first) - zone->second.m_net_server.get_config_object().notify(command, data_buff, c_id.second); + zone->second.m_net_server.get_config_object().send(message.clone(), c_id.second); } return true; } @@ -2255,24 +2262,13 @@ namespace nodetool } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> - bool node_server<t_payload_net_handler>::invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context) + bool node_server<t_payload_net_handler>::invoke_notify_to_peer(const int command, epee::levin::message_writer message, const epee::net_utils::connection_context_base& context) { if(is_filtered_command(context.m_remote_address, command)) return false; network_zone& zone = m_network_zones.at(context.m_remote_address.get_zone()); - int res = zone.m_net_server.get_config_object().notify(command, req_buff, context.m_connection_id); - return res > 0; - } - //----------------------------------------------------------------------------------- - template<class t_payload_net_handler> - bool node_server<t_payload_net_handler>::invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context) - { - if(is_filtered_command(context.m_remote_address, command)) - return false; - - network_zone& zone = m_network_zones.at(context.m_remote_address.get_zone()); - int res = zone.m_net_server.get_config_object().invoke(command, req_buff, resp_buff, context.m_connection_id); + int res = zone.m_net_server.get_config_object().send(message.finalize_notify(command), context.m_connection_id); return res > 0; } //----------------------------------------------------------------------------------- @@ -2458,14 +2454,12 @@ namespace nodetool template<class t_payload_net_handler> int node_server<t_payload_net_handler>::handle_handshake(int command, typename COMMAND_HANDSHAKE::request& arg, typename COMMAND_HANDSHAKE::response& rsp, p2p_connection_context& context) { - // copy since dropping the connection will invalidate the context, and thus the address - const auto remote_address = context.m_remote_address; - if(arg.node_data.network_id != m_network_id) { + LOG_INFO_CC(context, "WRONG NETWORK AGENT CONNECTED! id=" << arg.node_data.network_id); drop_connection(context); - add_host_fail(remote_address); + add_host_fail(context.m_remote_address); return 1; } @@ -2473,7 +2467,7 @@ namespace nodetool { LOG_WARNING_CC(context, "COMMAND_HANDSHAKE came not from incoming connection"); drop_connection(context); - add_host_fail(remote_address); + add_host_fail(context.m_remote_address); return 1; } diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h index 0da758ad4..92b7596ae 100644 --- a/src/p2p/net_node_common.h +++ b/src/p2p/net_node_common.h @@ -40,6 +40,8 @@ #include "net/net_utils_base.h" #include "p2p_protocol_defs.h" +namespace epee { namespace levin { class message_writer; } } + namespace nodetool { @@ -49,10 +51,9 @@ namespace nodetool template<class t_connection_context> struct i_p2p_endpoint { - virtual bool relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> connections)=0; + virtual bool relay_notify_to_list(int command, epee::levin::message_writer message, std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> connections)=0; virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::relay_method tx_relay)=0; - virtual bool invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)=0; - virtual bool invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context)=0; + virtual bool invoke_notify_to_peer(int command, epee::levin::message_writer message, const epee::net_utils::connection_context_base& context)=0; virtual bool drop_connection(const epee::net_utils::connection_context_base& context)=0; virtual void request_callback(const epee::net_utils::connection_context_base& context)=0; virtual uint64_t get_public_connections_count()=0; @@ -71,7 +72,7 @@ namespace nodetool template<class t_connection_context> struct p2p_endpoint_stub: public i_p2p_endpoint<t_connection_context> { - virtual bool relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> connections) + virtual bool relay_notify_to_list(int command, epee::levin::message_writer message, std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> connections) { return false; } @@ -79,11 +80,7 @@ namespace nodetool { return epee::net_utils::zone::invalid; } - virtual bool invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context) - { - return false; - } - virtual bool invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context) + virtual bool invoke_notify_to_peer(int command, epee::levin::message_writer message, const epee::net_utils::connection_context_base& context) { return true; } diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h index c794b0f3b..d8de6abe9 100644 --- a/src/p2p/net_peerlist.h +++ b/src/p2p/net_peerlist.h @@ -110,7 +110,7 @@ namespace nodetool bool get_gray_peer_by_index(peerlist_entry& p, size_t i); template<typename F> bool foreach(bool white, const F &f); void evict_host_from_white_peerlist(const peerlist_entry& pr); - bool append_with_peer_white(const peerlist_entry& pr); + bool append_with_peer_white(const peerlist_entry& pr, bool trust_last_seen = false); bool append_with_peer_gray(const peerlist_entry& pr); bool append_with_peer_anchor(const anchor_peerlist_entry& ple); bool set_peer_just_seen(peerid_type peer, const epee::net_utils::network_address& addr, uint32_t pruning_seed, uint16_t rpc_port, uint32_t rpc_credits_per_hash); @@ -329,12 +329,12 @@ namespace nodetool ple.pruning_seed = pruning_seed; ple.rpc_port = rpc_port; ple.rpc_credits_per_hash = rpc_credits_per_hash; - return append_with_peer_white(ple); + return append_with_peer_white(ple, true); CATCH_ENTRY_L0("peerlist_manager::set_peer_just_seen()", false); } //-------------------------------------------------------------------------------------------------- inline - bool peerlist_manager::append_with_peer_white(const peerlist_entry& ple) + bool peerlist_manager::append_with_peer_white(const peerlist_entry& ple, bool trust_last_seen) { TRY_ENTRY(); if(!is_host_allowed(ple.adr)) @@ -357,7 +357,8 @@ namespace nodetool new_ple.pruning_seed = by_addr_it_wt->pruning_seed; if (by_addr_it_wt->rpc_port && ple.rpc_port == 0) // guard against older nodes not passing RPC port around new_ple.rpc_port = by_addr_it_wt->rpc_port; - new_ple.last_seen = by_addr_it_wt->last_seen; // do not overwrite the last seen timestamp, incoming peer list are untrusted + if (!trust_last_seen) + new_ple.last_seen = by_addr_it_wt->last_seen; // do not overwrite the last seen timestamp, incoming peer lists are untrusted m_peers_white.replace(by_addr_it_wt, new_ple); } //remove from gray list, if need diff --git a/src/rpc/bootstrap_daemon.cpp b/src/rpc/bootstrap_daemon.cpp index 2fdd28406..ffea906d5 100644 --- a/src/rpc/bootstrap_daemon.cpp +++ b/src/rpc/bootstrap_daemon.cpp @@ -7,6 +7,7 @@ #include "crypto/crypto.h" #include "cryptonote_core/cryptonote_core.h" #include "misc_log_ex.h" +#include "net/parse.h" #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "daemon.rpc.bootstrap_daemon" @@ -16,19 +17,23 @@ namespace cryptonote bootstrap_daemon::bootstrap_daemon( std::function<std::map<std::string, bool>()> get_public_nodes, - bool rpc_payment_enabled) + bool rpc_payment_enabled, + const std::string &proxy) : m_selector(new bootstrap_node::selector_auto(std::move(get_public_nodes))) , m_rpc_payment_enabled(rpc_payment_enabled) { + set_proxy(proxy); } bootstrap_daemon::bootstrap_daemon( const std::string &address, boost::optional<epee::net_utils::http::login> credentials, - bool rpc_payment_enabled) + bool rpc_payment_enabled, + const std::string &proxy) : m_selector(nullptr) , m_rpc_payment_enabled(rpc_payment_enabled) { + set_proxy(proxy); if (!set_server(address, std::move(credentials))) { throw std::runtime_error("invalid bootstrap daemon address or credentials"); @@ -78,6 +83,18 @@ namespace cryptonote return success; } + void bootstrap_daemon::set_proxy(const std::string &address) + { + if (!address.empty() && !net::get_tcp_endpoint(address)) + { + throw std::runtime_error("invalid proxy address format"); + } + if (!m_http_client.set_proxy(address)) + { + throw std::runtime_error("failed to set proxy address"); + } + } + bool bootstrap_daemon::set_server(const std::string &address, const boost::optional<epee::net_utils::http::login> &credentials /* = boost::none */) { if (!m_http_client.set_server(address, credentials)) diff --git a/src/rpc/bootstrap_daemon.h b/src/rpc/bootstrap_daemon.h index d54042b11..1e4477123 100644 --- a/src/rpc/bootstrap_daemon.h +++ b/src/rpc/bootstrap_daemon.h @@ -8,7 +8,7 @@ #include <boost/thread/mutex.hpp> #include <boost/utility/string_ref.hpp> -#include "net/http_client.h" +#include "net/http.h" #include "storages/http_abstract_invoke.h" #include "bootstrap_node_selector.h" @@ -21,11 +21,13 @@ namespace cryptonote public: bootstrap_daemon( std::function<std::map<std::string, bool>()> get_public_nodes, - bool rpc_payment_enabled); + bool rpc_payment_enabled, + const std::string &proxy); bootstrap_daemon( const std::string &address, boost::optional<epee::net_utils::http::login> credentials, - bool rpc_payment_enabled); + bool rpc_payment_enabled, + const std::string &proxy); std::string address() const noexcept; boost::optional<std::pair<uint64_t, uint64_t>> get_height(); @@ -72,12 +74,14 @@ namespace cryptonote return handle_result(result, result_struct.status); } + void set_proxy(const std::string &address); + private: bool set_server(const std::string &address, const boost::optional<epee::net_utils::http::login> &credentials = boost::none); bool switch_server_if_needed(); private: - epee::net_utils::http::http_simple_client m_http_client; + net::http::client m_http_client; const bool m_rpc_payment_enabled; const std::unique_ptr<bootstrap_node::selector> m_selector; boost::mutex m_selector_mutex; diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 0c6e2ec8f..ded545efa 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -30,6 +30,7 @@ #include <boost/preprocessor/stringize.hpp> #include <boost/uuid/nil_generator.hpp> +#include <boost/filesystem.hpp> #include "include_base_utils.h" #include "string_tools.h" using namespace epee; @@ -155,6 +156,7 @@ namespace cryptonote 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); + command_line::add_arg(desc, arg_bootstrap_daemon_proxy); cryptonote::rpc_args::init_options(desc, true); command_line::add_arg(desc, arg_rpc_payment_address); command_line::add_arg(desc, arg_rpc_payment_difficulty); @@ -173,7 +175,10 @@ namespace cryptonote , m_rpc_payment_allow_free_loopback(false) {} //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::set_bootstrap_daemon(const std::string &address, const std::string &username_password) + bool core_rpc_server::set_bootstrap_daemon( + const std::string &address, + const std::string &username_password, + const std::string &proxy) { boost::optional<epee::net_utils::http::login> credentials; const auto loc = username_password.find(':'); @@ -181,7 +186,7 @@ namespace cryptonote { credentials = epee::net_utils::http::login(username_password.substr(0, loc), username_password.substr(loc + 1)); } - return set_bootstrap_daemon(address, credentials); + return set_bootstrap_daemon(address, credentials, proxy); } //------------------------------------------------------------------------------------------------------------------------------ std::map<std::string, bool> core_rpc_server::get_public_nodes(uint32_t credits_per_hash_threshold/* = 0*/) @@ -218,7 +223,10 @@ namespace cryptonote return result; } //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::set_bootstrap_daemon(const std::string &address, const boost::optional<epee::net_utils::http::login> &credentials) + bool core_rpc_server::set_bootstrap_daemon( + const std::string &address, + const boost::optional<epee::net_utils::http::login> &credentials, + const std::string &proxy) { boost::unique_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex); @@ -234,11 +242,11 @@ namespace cryptonote auto get_nodes = [this]() { return get_public_nodes(credits_per_hash_threshold); }; - m_bootstrap_daemon.reset(new bootstrap_daemon(std::move(get_nodes), rpc_payment_enabled)); + m_bootstrap_daemon.reset(new bootstrap_daemon(std::move(get_nodes), rpc_payment_enabled, proxy)); } else { - m_bootstrap_daemon.reset(new bootstrap_daemon(address, credentials, rpc_payment_enabled)); + m_bootstrap_daemon.reset(new bootstrap_daemon(address, credentials, rpc_payment_enabled, proxy)); } m_should_use_bootstrap_daemon = m_bootstrap_daemon.get() != nullptr; @@ -320,8 +328,10 @@ namespace cryptonote MWARNING("The RPC server is accessible from the outside, but no RPC payment was setup. RPC access will be free for all."); } - if (!set_bootstrap_daemon(command_line::get_arg(vm, arg_bootstrap_daemon_address), - command_line::get_arg(vm, arg_bootstrap_daemon_login))) + if (!set_bootstrap_daemon( + command_line::get_arg(vm, arg_bootstrap_daemon_address), + command_line::get_arg(vm, arg_bootstrap_daemon_login), + command_line::get_arg(vm, arg_bootstrap_daemon_proxy))) { MFATAL("Failed to parse bootstrap daemon address"); return false; @@ -595,7 +605,7 @@ namespace cryptonote if (max_blocks == 0) { res.status = CORE_RPC_STATUS_PAYMENT_REQUIRED; - return false; + return true; } } @@ -604,7 +614,7 @@ namespace cryptonote { res.status = "Failed"; add_host_fail(ctx); - return false; + return true; } CHECK_PAYMENT_SAME_TS(req, res, bs.size() * COST_PER_BLOCK); @@ -640,12 +650,12 @@ namespace cryptonote if (!r) { res.status = "Failed"; - return false; + return true; } if (indices.size() != n_txes_to_lookup || res.output_indices.back().indices.size() != (req.no_miner_tx ? 1 : 0)) { res.status = "Failed"; - return false; + return true; } for (size_t i = 0; i < indices.size(); ++i) res.output_indices.back().indices.push_back({std::move(indices[i])}); @@ -668,7 +678,7 @@ namespace cryptonote if(!m_core.get_alternative_blocks(blks)) { res.status = "Failed"; - return false; + return true; } res.blks_hashes.reserve(blks.size()); @@ -739,7 +749,7 @@ namespace cryptonote { res.status = "Failed"; add_host_fail(ctx); - return false; + return true; } CHECK_PAYMENT_SAME_TS(req, res, res.m_block_ids.size() * COST_PER_BLOCK_HASH); @@ -1070,7 +1080,7 @@ namespace cryptonote if (!r) { res.status = "Failed"; - return false; + return true; } } } @@ -1446,7 +1456,8 @@ namespace cryptonote res.status = peer_list_res.status; if (!success) { - return false; + res.status = "Failed to get peer list"; + return true; } if (res.status != CORE_RPC_STATUS_OK) { @@ -1617,15 +1628,15 @@ namespace cryptonote { credentials = epee::net_utils::http::login(req.username, req.password); } - - if (set_bootstrap_daemon(req.address, credentials)) + + if (set_bootstrap_daemon(req.address, credentials, req.proxy)) { res.status = CORE_RPC_STATUS_OK; } else { res.status = "Failed to set bootstrap daemon"; - } + } return true; } @@ -1648,7 +1659,7 @@ namespace cryptonote if (m_should_use_bootstrap_daemon) { res.status = "This command is unsupported for bootstrap daemon"; - return false; + return true; } } res.count = m_core.get_current_blockchain_height(); @@ -1664,7 +1675,7 @@ namespace cryptonote if (m_should_use_bootstrap_daemon) { res = "This command is unsupported for bootstrap daemon"; - return false; + return true; } } if(req.size() != 1) @@ -1974,7 +1985,8 @@ namespace cryptonote 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"; + error_resp.code = CORE_RPC_ERROR_CODE_UNSUPPORTED_BOOTSTRAP; + error_resp.message = "This command is unsupported for bootstrap daemon"; return false; } } @@ -2666,7 +2678,7 @@ namespace cryptonote if (!m_core.get_blockchain_storage().flush_txes_from_pool(txids)) { res.status = "Failed to remove one or more tx(es)"; - return false; + return true; } if (failed) @@ -2675,7 +2687,7 @@ namespace cryptonote res.status = "Failed to parse txid"; else res.status = "Failed to parse some of the txids"; - return false; + return true; } res.status = CORE_RPC_STATUS_OK; @@ -2834,7 +2846,7 @@ namespace cryptonote if (req.limit_down != -1) { res.status = CORE_RPC_ERROR_CODE_WRONG_PARAM; - return false; + return true; } epee::net_utils::connection_basic::set_rate_down_limit(nodetool::default_limit_down); } @@ -2848,7 +2860,7 @@ namespace cryptonote if (req.limit_up != -1) { res.status = CORE_RPC_ERROR_CODE_WRONG_PARAM; - return false; + return true; } epee::net_utils::connection_basic::set_rate_up_limit(nodetool::default_limit_up); } @@ -2952,17 +2964,17 @@ namespace cryptonote if (!tools::download(path.string(), res.auto_uri)) { MERROR("Failed to download " << res.auto_uri); - return false; + return true; } if (!tools::sha256sum(path.string(), file_hash)) { MERROR("Failed to hash " << path); - return false; + return true; } if (hash != epee::string_tools::pod_to_hex(file_hash)) { MERROR("Download from " << res.auto_uri << " does not match the expected hash"); - return false; + return true; } MINFO("New version downloaded to " << path); } @@ -3037,6 +3049,8 @@ namespace cryptonote if (failed) { + error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; + error_resp.message = res.status; return false; } @@ -3148,7 +3162,7 @@ namespace cryptonote if (!req.binary) { res.status = "Binary only call"; - return false; + return true; } try { @@ -3160,7 +3174,7 @@ namespace cryptonote if (!data) { res.status = "Failed to get output distribution"; - return false; + return true; } res.distributions.push_back({std::move(*data), amount, "", req.binary, req.compress}); @@ -3169,7 +3183,7 @@ namespace cryptonote catch (const std::exception &e) { res.status = "Failed to get output distribution"; - return false; + return true; } res.status = CORE_RPC_STATUS_OK; @@ -3403,7 +3417,8 @@ namespace cryptonote if (!m_rpc_payment) { - res.status = "Payments not enabled"; + error_resp.code = CORE_RPC_ERROR_CODE_PAYMENTS_NOT_ENABLED; + error_resp.message = "Payments not enabled"; return false; } @@ -3431,7 +3446,8 @@ namespace cryptonote if (!m_rpc_payment) { - res.status = "Payments not enabled"; + error_resp.code = CORE_RPC_ERROR_CODE_PAYMENTS_NOT_ENABLED; + error_resp.message = "Payments not enabled"; return false; } @@ -3488,6 +3504,12 @@ namespace cryptonote , "" }; + const command_line::arg_descriptor<std::string> core_rpc_server::arg_bootstrap_daemon_proxy = { + "bootstrap-daemon-proxy" + , "<ip>:<port> socks proxy to use for bootstrap daemon connections" + , "" + }; + const command_line::arg_descriptor<std::string> core_rpc_server::arg_rpc_payment_address = { "rpc-payment-address" , "Restrict RPC to clients sending micropayment to this address" diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index 6736a6b7f..b21e43ab0 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -72,6 +72,7 @@ namespace cryptonote static const command_line::arg_descriptor<bool> arg_rpc_ssl_allow_any_cert; static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_address; static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_login; + static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_proxy; static const command_line::arg_descriptor<std::string> arg_rpc_payment_address; static const command_line::arg_descriptor<uint64_t> arg_rpc_payment_difficulty; static const command_line::arg_descriptor<uint64_t> arg_rpc_payment_credits; @@ -270,8 +271,14 @@ private: 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, bool fill_pow_hash); std::map<std::string, bool> get_public_nodes(uint32_t credits_per_hash_threshold = 0); - bool set_bootstrap_daemon(const std::string &address, const std::string &username_password); - bool set_bootstrap_daemon(const std::string &address, const boost::optional<epee::net_utils::http::login> &credentials); + bool set_bootstrap_daemon( + const std::string &address, + const std::string &username_password, + const std::string &proxy); + bool set_bootstrap_daemon( + const std::string &address, + const boost::optional<epee::net_utils::http::login> &credentials, + const std::string &proxy); 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); diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index e7bcb5570..5ebe4f654 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -1659,11 +1659,13 @@ namespace cryptonote std::string address; std::string username; std::string password; + std::string proxy; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(address) KV_SERIALIZE(username) KV_SERIALIZE(password) + KV_SERIALIZE(proxy) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; diff --git a/src/rpc/core_rpc_server_error_codes.h b/src/rpc/core_rpc_server_error_codes.h index 1458049ab..232df0373 100644 --- a/src/rpc/core_rpc_server_error_codes.h +++ b/src/rpc/core_rpc_server_error_codes.h @@ -49,6 +49,8 @@ #define CORE_RPC_ERROR_CODE_DUPLICATE_PAYMENT -17 #define CORE_RPC_ERROR_CODE_STALE_PAYMENT -18 #define CORE_RPC_ERROR_CODE_RESTRICTED -19 +#define CORE_RPC_ERROR_CODE_UNSUPPORTED_BOOTSTRAP -20 +#define CORE_RPC_ERROR_CODE_PAYMENTS_NOT_ENABLED -21 static inline const char *get_rpc_server_error_message(int64_t code) { @@ -72,6 +74,8 @@ static inline const char *get_rpc_server_error_message(int64_t code) case CORE_RPC_ERROR_CODE_DUPLICATE_PAYMENT: return "Duplicate payment"; case CORE_RPC_ERROR_CODE_STALE_PAYMENT: return "Stale payment"; case CORE_RPC_ERROR_CODE_RESTRICTED: return "Parameters beyond restricted allowance"; + case CORE_RPC_ERROR_CODE_UNSUPPORTED_BOOTSTRAP: return "Command is unsupported in bootstrap mode"; + case CORE_RPC_ERROR_CODE_PAYMENTS_NOT_ENABLED: return "Payments not enabled"; default: MERROR("Unknown error: " << code); return "Unknown error"; } } diff --git a/src/rpc/rpc_payment.cpp b/src/rpc/rpc_payment.cpp index 176f11fa3..bf6584f72 100644 --- a/src/rpc/rpc_payment.cpp +++ b/src/rpc/rpc_payment.cpp @@ -27,6 +27,7 @@ // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <boost/archive/portable_binary_iarchive.hpp> +#include <boost/filesystem.hpp> #include "cryptonote_config.h" #include "include_base_utils.h" #include "string_tools.h" diff --git a/src/serialization/binary_archive.h b/src/serialization/binary_archive.h index 80104c8f7..49ca8aa57 100644 --- a/src/serialization/binary_archive.h +++ b/src/serialization/binary_archive.h @@ -98,7 +98,7 @@ template <> struct binary_archive<false> : public binary_archive_base<std::istream, false> { - explicit binary_archive(stream_type &s) : base_type(s) { + explicit binary_archive(stream_type &s) : base_type(s), varint_bug_backward_compatibility_(false) { stream_type::pos_type pos = stream_.tellg(); stream_.seekg(0, std::ios_base::end); eof_pos_ = stream_.tellg(); @@ -173,8 +173,13 @@ struct binary_archive<false> : public binary_archive_base<std::istream, false> assert(stream_.tellg() <= eof_pos_); return eof_pos_ - stream_.tellg(); } + + void enable_varint_bug_backward_compatibility() { varint_bug_backward_compatibility_ = true; } + bool varint_bug_backward_compatibility_enabled() const { return varint_bug_backward_compatibility_; } + protected: std::streamoff eof_pos_; + bool varint_bug_backward_compatibility_; }; template <> @@ -227,6 +232,8 @@ struct binary_archive<true> : public binary_archive_base<std::ostream, true> void write_variant_tag(variant_tag_type t) { serialize_int(t); } + + bool varint_bug_backward_compatibility_enabled() const { return false; } }; POP_WARNINGS diff --git a/src/serialization/container.h b/src/serialization/container.h index d5e75bb4f..a4997c8ae 100644 --- a/src/serialization/container.h +++ b/src/serialization/container.h @@ -32,22 +32,27 @@ namespace serialization { namespace detail { - template <typename Archive, class T> - bool serialize_container_element(Archive& ar, T& e) + template<typename T> + inline constexpr bool use_container_varint() noexcept { - return ::do_serialize(ar, e); + return std::is_integral<T>::value && std::is_unsigned<T>::value && sizeof(T) > 1; } - template <typename Archive> - bool serialize_container_element(Archive& ar, uint32_t& e) + template <typename Archive, class T> + typename std::enable_if<!use_container_varint<T>(), bool>::type + serialize_container_element(Archive& ar, T& e) { - ar.serialize_varint(e); - return true; + return ::do_serialize(ar, e); } - template <typename Archive> - bool serialize_container_element(Archive& ar, uint64_t& e) + template<typename Archive, typename T> + typename std::enable_if<use_container_varint<T>(), bool>::type + serialize_container_element(Archive& ar, T& e) { + static constexpr const bool previously_varint = std::is_same<uint64_t, T>() || std::is_same<uint32_t, T>(); + + if (!previously_varint && ar.varint_bug_backward_compatibility_enabled() && !typename Archive::is_saving()) + return ::do_serialize(ar, e); ar.serialize_varint(e); return true; } diff --git a/src/serialization/json_archive.h b/src/serialization/json_archive.h index 50dd5bbd0..3f98b5101 100644 --- a/src/serialization/json_archive.h +++ b/src/serialization/json_archive.h @@ -84,6 +84,8 @@ struct json_archive_base void end_variant() { end_object(); } Stream &stream() { return stream_; } + bool varint_bug_backward_compatibility_enabled() const { return false; } + protected: void make_indent() { diff --git a/src/serialization/pair.h b/src/serialization/pair.h index 18280d837..44aafa04d 100644 --- a/src/serialization/pair.h +++ b/src/serialization/pair.h @@ -30,21 +30,34 @@ #pragma once #include <memory> +#include <boost/type_traits/make_unsigned.hpp> #include "serialization.h" namespace serialization { namespace detail { + template<typename T> + inline constexpr bool use_pair_varint() noexcept + { + return std::is_integral<T>::value && std::is_unsigned<T>::value && sizeof(T) > 1; + } + template <typename Archive, class T> - bool serialize_pair_element(Archive& ar, T& e) + typename std::enable_if<!use_pair_varint<T>(), bool>::type + serialize_pair_element(Archive& ar, T& e) { return ::do_serialize(ar, e); } - template <typename Archive> - bool serialize_pair_element(Archive& ar, uint64_t& e) + template<typename Archive, typename T> + typename std::enable_if<use_pair_varint<T>(), bool>::type + serialize_pair_element(Archive& ar, T& e) { + static constexpr const bool previously_varint = std::is_same<uint64_t, T>(); + + if (!previously_varint && ar.varint_bug_backward_compatibility_enabled() && !typename Archive::is_saving()) + return ::do_serialize(ar, e); ar.serialize_varint(e); return true; } diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 2a3c33f48..da6501183 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -50,6 +50,7 @@ #include <boost/format.hpp> #include <boost/regex.hpp> #include <boost/range/adaptor/transformed.hpp> +#include <boost/filesystem.hpp> #include "include_base_utils.h" #include "console_handler.h" #include "common/i18n.h" @@ -276,7 +277,7 @@ namespace const char* USAGE_PUBLIC_NODES("public_nodes"); const char* USAGE_WELCOME("welcome"); const char* USAGE_RPC_PAYMENT_INFO("rpc_payment_info"); - const char* USAGE_START_MINING_FOR_RPC("start_mining_for_rpc"); + const char* USAGE_START_MINING_FOR_RPC("start_mining_for_rpc [<number_of_threads>]"); const char* USAGE_STOP_MINING_FOR_RPC("stop_mining_for_rpc"); const char* USAGE_SHOW_QR_CODE("show_qr_code [<subaddress_index>]"); const char* USAGE_VERSION("version"); @@ -2361,6 +2362,24 @@ bool simple_wallet::start_mining_for_rpc(const std::vector<std::string> &args) if (!try_connect_to_daemon()) return true; + bool ok = true; + if(args.size() >= 1) + { + uint16_t num = 0; + ok = string_tools::get_xtype_from_string(num, args[0]); + m_rpc_payment_threads = num; + } + else + { + m_rpc_payment_threads = 0; + } + + if (!ok) + { + PRINT_USAGE(USAGE_START_MINING_FOR_RPC); + return true; + } + LOCK_IDLE_SCOPE(); bool payment_required; @@ -9327,7 +9346,7 @@ bool simple_wallet::check_rpc_payment() fail_msg_writer() << tr("Error mining to daemon: ") << error; m_cmd_binder.print_prompt(); }; - bool ret = m_wallet->search_for_rpc_payment(target, startfunc, contfunc, foundfunc, errorfunc); + bool ret = m_wallet->search_for_rpc_payment(target, m_rpc_payment_threads, startfunc, contfunc, foundfunc, errorfunc); if (!ret) { fail_msg_writer() << tr("Failed to start mining for RPC payment"); diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index af654e0dd..8780bee1d 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -464,6 +464,7 @@ namespace cryptonote std::atomic<bool> m_need_payment; boost::posix_time::ptime m_last_rpc_payment_mining_time; bool m_rpc_payment_mining_requested; + uint32_t m_rpc_payment_threads = 0; bool m_daemon_rpc_payment_message_displayed; float m_rpc_payment_hash_rate; std::atomic<bool> m_suspend_rpc_payment_mining; diff --git a/src/wallet/api/pending_transaction.cpp b/src/wallet/api/pending_transaction.cpp index 24f6d37db..b28ffd64c 100644 --- a/src/wallet/api/pending_transaction.cpp +++ b/src/wallet/api/pending_transaction.cpp @@ -40,6 +40,7 @@ #include <vector> #include <sstream> #include <boost/format.hpp> +#include <boost/filesystem.hpp> using namespace std; diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 4f923ce54..3bbd9ce0b 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -45,10 +45,8 @@ #include <sstream> #include <unordered_map> -#ifdef WIN32 #include <boost/locale.hpp> #include <boost/filesystem.hpp> -#endif using namespace std; using namespace cryptonote; @@ -791,11 +789,11 @@ bool WalletImpl::close(bool store) return result; } -std::string WalletImpl::seed() const +std::string WalletImpl::seed(const std::string& seed_offset) const { epee::wipeable_string seed; if (m_wallet) - m_wallet->get_seed(seed); + m_wallet->get_seed(seed, seed_offset); return std::string(seed.data(), seed.size()); // TODO } @@ -2104,6 +2102,11 @@ bool WalletImpl::watchOnly() const return m_wallet->watch_only(); } +bool WalletImpl::isDeterministic() const +{ + return m_wallet->is_deterministic(); +} + void WalletImpl::clearStatus() const { boost::lock_guard<boost::mutex> l(m_statusMutex); diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index e501d3943..0f3614bb4 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -81,7 +81,7 @@ public: const std::string &device_name); Device getDeviceType() const override; bool close(bool store = true); - std::string seed() const override; + std::string seed(const std::string& seed_offset = "") const override; std::string getSeedLanguage() const override; void setSeedLanguage(const std::string &arg) override; // void setListener(Listener *) {} @@ -129,6 +129,7 @@ public: void setRecoveringFromDevice(bool recoveringFromDevice) override; void setSubaddressLookahead(uint32_t major, uint32_t minor) override; bool watchOnly() const override; + bool isDeterministic() const override; bool rescanSpent() override; NetworkType nettype() const override {return static_cast<NetworkType>(m_wallet->nettype());} void hardForkInfo(uint8_t &version, uint64_t &earliest_height) const override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index b40b6763f..b1cebedaf 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -446,7 +446,7 @@ struct Wallet }; virtual ~Wallet() = 0; - virtual std::string seed() const = 0; + virtual std::string seed(const std::string& seed_offset = "") const = 0; virtual std::string getSeedLanguage() const = 0; virtual void setSeedLanguage(const std::string &arg) = 0; //! returns wallet status (Status_Ok | Status_Error) @@ -627,6 +627,12 @@ struct Wallet virtual bool watchOnly() const = 0; /** + * @brief isDeterministic - checks if wallet keys are deterministic + * @return - true if deterministic + */ + virtual bool isDeterministic() const = 0; + + /** * @brief blockChainHeight - returns current blockchain height * @return */ diff --git a/src/wallet/message_store.cpp b/src/wallet/message_store.cpp index 87cb75fbf..b7b29420b 100644 --- a/src/wallet/message_store.cpp +++ b/src/wallet/message_store.cpp @@ -30,6 +30,8 @@ #include <boost/archive/portable_binary_iarchive.hpp> #include <boost/format.hpp> #include <boost/algorithm/string.hpp> +#include <boost/system/error_code.hpp> +#include <boost/filesystem.hpp> #include <fstream> #include <sstream> #include "file_io_utils.h" diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index e298eca53..0af896c76 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -5706,6 +5706,16 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass if (::serialization::serialize(ar, *this)) if (::serialization::check_stream_state(ar)) loaded = true; + if (!loaded) + { + std::stringstream iss; + iss << cache_data; + binary_archive<false> ar(iss); + ar.enable_varint_bug_backward_compatibility(); + if (::serialization::serialize(ar, *this)) + if (::serialization::check_stream_state(ar)) + loaded = true; + } } catch(...) { } @@ -6025,7 +6035,7 @@ uint64_t wallet2::balance(uint32_t index_major, bool strict) const { uint64_t amount = 0; if(m_light_wallet) - return m_light_wallet_unlocked_balance; + return m_light_wallet_balance; for (const auto& i : balance_per_subaddress(index_major, strict)) amount += i.second; return amount; @@ -6039,7 +6049,7 @@ uint64_t wallet2::unlocked_balance(uint32_t index_major, bool strict, uint64_t * if (time_to_unlock) *time_to_unlock = 0; if(m_light_wallet) - return m_light_wallet_balance; + return m_light_wallet_unlocked_balance; for (const auto& i : unlocked_balance_per_subaddress(index_major, strict)) { amount += i.second.first; @@ -12528,7 +12538,7 @@ crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::walle bool wallet2::export_key_images(const std::string &filename, bool all) const { PERF_TIMER(export_key_images); - std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = export_key_images(all); + std::pair<uint64_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = export_key_images(all); std::string magic(KEY_IMAGE_EXPORT_FILE_MAGIC, strlen(KEY_IMAGE_EXPORT_FILE_MAGIC)); const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address; const uint32_t offset = ski.first; @@ -12555,7 +12565,7 @@ bool wallet2::export_key_images(const std::string &filename, bool all) const } //---------------------------------------------------------------------------------------------------- -std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> wallet2::export_key_images(bool all) const +std::pair<uint64_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> wallet2::export_key_images(bool all) const { PERF_TIMER(export_key_images_raw); std::vector<std::pair<crypto::key_image, crypto::signature>> ski; @@ -13052,7 +13062,7 @@ void wallet2::import_blockchain(const std::tuple<size_t, crypto::hash, std::vect m_last_block_reward = cryptonote::get_outs_money_amount(genesis.miner_tx); } //---------------------------------------------------------------------------------------------------- -std::pair<size_t, std::vector<tools::wallet2::transfer_details>> wallet2::export_outputs(bool all) const +std::pair<uint64_t, std::vector<tools::wallet2::transfer_details>> wallet2::export_outputs(bool all) const { PERF_TIMER(export_outputs); std::vector<tools::wallet2::transfer_details> outs; @@ -13092,7 +13102,7 @@ std::string wallet2::export_outputs_to_str(bool all) const return magic + ciphertext; } //---------------------------------------------------------------------------------------------------- -size_t wallet2::import_outputs(const std::pair<size_t, std::vector<tools::wallet2::transfer_details>> &outputs) +size_t wallet2::import_outputs(const std::pair<uint64_t, std::vector<tools::wallet2::transfer_details>> &outputs) { PERF_TIMER(import_outputs); @@ -13198,7 +13208,7 @@ size_t wallet2::import_outputs_from_str(const std::string &outputs_st) try { std::string body(data, headerlen); - std::pair<size_t, std::vector<tools::wallet2::transfer_details>> outputs; + std::pair<uint64_t, std::vector<tools::wallet2::transfer_details>> outputs; try { std::stringstream iss; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index e5a5136a4..e96a6b51c 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -327,7 +327,7 @@ private: uint64_t m_block_height; cryptonote::transaction_prefix m_tx; crypto::hash m_txid; - size_t m_internal_output_index; + uint64_t m_internal_output_index; uint64_t m_global_output_index; bool m_spent; bool m_frozen; @@ -338,7 +338,7 @@ private: bool m_rct; bool m_key_image_known; bool m_key_image_request; // view wallets: we want to request it; cold wallets: it was requested - size_t m_pk_index; + uint64_t m_pk_index; cryptonote::subaddress_index m_subaddr_index; bool m_key_image_partial; std::vector<rct::key> m_multisig_k; @@ -1372,9 +1372,9 @@ private: bool verify_with_public_key(const std::string &data, const crypto::public_key &public_key, const std::string &signature) const; // Import/Export wallet data - std::pair<size_t, std::vector<tools::wallet2::transfer_details>> export_outputs(bool all = false) const; + std::pair<uint64_t, std::vector<tools::wallet2::transfer_details>> export_outputs(bool all = false) const; std::string export_outputs_to_str(bool all = false) const; - size_t import_outputs(const std::pair<size_t, std::vector<tools::wallet2::transfer_details>> &outputs); + size_t import_outputs(const std::pair<uint64_t, std::vector<tools::wallet2::transfer_details>> &outputs); size_t import_outputs_from_str(const std::string &outputs_st); payment_container export_payments() const; void import_payments(const payment_container &payments); @@ -1382,7 +1382,7 @@ private: std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> export_blockchain() const; void import_blockchain(const std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> &bc); bool export_key_images(const std::string &filename, bool all = false) const; - std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> export_key_images(bool all = false) const; + std::pair<uint64_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> export_key_images(bool all = false) const; uint64_t import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, size_t offset, uint64_t &spent, uint64_t &unspent, bool check_spent = true); uint64_t import_key_images(const std::string &filename, uint64_t &spent, uint64_t &unspent); bool import_key_images(std::vector<crypto::key_image> key_images, size_t offset=0, boost::optional<std::unordered_set<size_t>> selected_transfers=boost::none); @@ -1428,7 +1428,7 @@ private: bool get_rpc_payment_info(bool mining, bool &payment_required, uint64_t &credits, uint64_t &diff, uint64_t &credits_per_hash_found, cryptonote::blobdata &hashing_blob, uint64_t &height, uint64_t &seed_height, crypto::hash &seed_hash, crypto::hash &next_seed_hash, uint32_t &cookie); bool daemon_requires_payment(); bool make_rpc_payment(uint32_t nonce, uint32_t cookie, uint64_t &credits, uint64_t &balance); - bool search_for_rpc_payment(uint64_t credits_target, const std::function<bool(uint64_t, uint64_t)> &startfunc, const std::function<bool(unsigned)> &contfunc, const std::function<bool(uint64_t)> &foundfunc = NULL, const std::function<void(const std::string&)> &errorfunc = NULL); + bool search_for_rpc_payment(uint64_t credits_target, uint32_t n_threads, const std::function<bool(uint64_t, uint64_t)> &startfunc, const std::function<bool(unsigned)> &contfunc, const std::function<bool(uint64_t)> &foundfunc = NULL, const std::function<void(const std::string&)> &errorfunc = NULL); template<typename T> void handle_payment_changes(const T &res, std::true_type) { if (res.status == CORE_RPC_STATUS_OK || res.status == CORE_RPC_STATUS_PAYMENT_REQUIRED) m_rpc_payment_state.credits = res.credits; diff --git a/src/wallet/wallet_rpc_payments.cpp b/src/wallet/wallet_rpc_payments.cpp index 6527b1384..bf278f695 100644 --- a/src/wallet/wallet_rpc_payments.cpp +++ b/src/wallet/wallet_rpc_payments.cpp @@ -42,6 +42,7 @@ #include "cryptonote_basic/blobdatatype.h" #include "common/i18n.h" #include "common/util.h" +#include "common/threadpool.h" #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "wallet.wallet2.rpc_payments" @@ -101,7 +102,7 @@ bool wallet2::make_rpc_payment(uint32_t nonce, uint32_t cookie, uint64_t &credit return true; } //---------------------------------------------------------------------------------------------------- -bool wallet2::search_for_rpc_payment(uint64_t credits_target, const std::function<bool(uint64_t, uint64_t)> &startfunc, const std::function<bool(unsigned)> &contfunc, const std::function<bool(uint64_t)> &foundfunc, const std::function<void(const std::string&)> &errorfunc) +bool wallet2::search_for_rpc_payment(uint64_t credits_target, uint32_t n_threads, const std::function<bool(uint64_t, uint64_t)> &startfunc, const std::function<bool(unsigned)> &contfunc, const std::function<bool(uint64_t)> &foundfunc, const std::function<void(const std::string&)> &errorfunc) { bool need_payment = false; bool payment_required; @@ -139,49 +140,65 @@ bool wallet2::search_for_rpc_payment(uint64_t credits_target, const std::functio continue; } - crypto::hash hash; - const uint32_t local_nonce = nonce++; // wrapping's OK - *(uint32_t*)(hashing_blob.data() + 39) = SWAP32LE(local_nonce); - const uint8_t major_version = hashing_blob[0]; - if (major_version >= RX_BLOCK_VERSION) - { - const int miners = 1; - crypto::rx_slow_hash(height, seed_height, seed_hash.data, hashing_blob.data(), hashing_blob.size(), hash.data, miners, 0); - } - else + if(n_threads == 0) + n_threads = boost::thread::hardware_concurrency(); + + std::vector<crypto::hash> hash(n_threads); + tools::threadpool& tpool = tools::threadpool::getInstance(); + tools::threadpool::waiter waiter(tpool); + + const uint32_t local_nonce = nonce += n_threads; // wrapping's OK + for (size_t i = 0; i < n_threads; i++) { - int cn_variant = hashing_blob[0] >= 7 ? hashing_blob[0] - 6 : 0; - crypto::cn_slow_hash(hashing_blob.data(), hashing_blob.size(), hash, cn_variant, height); + tpool.submit(&waiter, [&, i] { + *(uint32_t*)(hashing_blob.data() + 39) = SWAP32LE(local_nonce-i); + const uint8_t major_version = hashing_blob[0]; + if (major_version >= RX_BLOCK_VERSION) + { + const int miners = 1; + crypto::rx_slow_hash(height, seed_height, seed_hash.data, hashing_blob.data(), hashing_blob.size(), hash[i].data, miners, 0); + } + else + { + int cn_variant = hashing_blob[0] >= 7 ? hashing_blob[0] - 6 : 0; + crypto::cn_slow_hash(hashing_blob.data(), hashing_blob.size(), hash[i], cn_variant, height); + } + }); } - ++n_hashes; - if (cryptonote::check_hash(hash, diff)) + waiter.wait(); + n_hashes += n_threads; + + for(size_t i=0; i < n_threads; i++) { - uint64_t credits, balance; - try + if (cryptonote::check_hash(hash[i], diff)) { - make_rpc_payment(local_nonce, cookie, credits, balance); - if (credits != credits_per_hash_found) + uint64_t credits, balance; + try { - MERROR("Found nonce, but daemon did not credit us with the expected amount"); + make_rpc_payment(local_nonce-i, cookie, credits, balance); + if (credits != credits_per_hash_found) + { + MERROR("Found nonce, but daemon did not credit us with the expected amount"); + if (errorfunc) + errorfunc("Found nonce, but daemon did not credit us with the expected amount"); + return false; + } + MDEBUG("Found nonce " << local_nonce-i << " at diff " << diff << ", gets us " << credits_per_hash_found << ", now " << balance << " credits"); + if (!foundfunc(credits)) + break; + } + catch (const tools::error::wallet_coded_rpc_error &e) + { + MWARNING("Found a local_nonce at diff " << diff << ", but failed to send it to the daemon"); if (errorfunc) - errorfunc("Found nonce, but daemon did not credit us with the expected amount"); - return false; + errorfunc("Found nonce, but daemon errored out with error " + std::to_string(e.code()) + ": " + e.status() + ", continuing"); + } + catch (const std::exception &e) + { + MWARNING("Found a local_nonce at diff " << diff << ", but failed to send it to the daemon"); + if (errorfunc) + errorfunc("Found nonce, but daemon errored out with: '" + std::string(e.what()) + "', continuing"); } - MDEBUG("Found nonce " << local_nonce << " at diff " << diff << ", gets us " << credits_per_hash_found << ", now " << balance << " credits"); - if (!foundfunc(credits)) - break; - } - catch (const tools::error::wallet_coded_rpc_error &e) - { - MWARNING("Found a local_nonce at diff " << diff << ", but failed to send it to the daemon"); - if (errorfunc) - errorfunc("Found nonce, but daemon errored out with error " + std::to_string(e.code()) + ": " + e.status() + ", continuing"); - } - catch (const std::exception &e) - { - MWARNING("Found a local_nonce at diff " << diff << ", but failed to send it to the daemon"); - if (errorfunc) - errorfunc("Found nonce, but daemon errored out with: '" + std::string(e.what()) + "', continuing"); } } } diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index b09e24d31..b39a40b64 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -2702,7 +2702,7 @@ namespace tools if (!m_wallet) return not_open(er); try { - std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = m_wallet->export_key_images(req.all); + std::pair<uint64_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = m_wallet->export_key_images(req.all); res.offset = ski.first; res.signed_key_images.resize(ski.second.size()); for (size_t n = 0; n < ski.second.size(); ++n) @@ -3154,17 +3154,7 @@ namespace tools } std::string wallet_file = req.filename.empty() ? "" : (m_wallet_dir + "/" + req.filename); { - std::vector<std::string> languages; - crypto::ElectrumWords::get_language_list(languages, false); - std::vector<std::string>::iterator it; - - it = std::find(languages.begin(), languages.end(), req.language); - if (it == languages.end()) - { - crypto::ElectrumWords::get_language_list(languages, true); - it = std::find(languages.begin(), languages.end(), req.language); - } - if (it == languages.end()) + if (!crypto::ElectrumWords::is_valid_language(req.language)) { er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; er.message = "Unknown language: " + req.language; @@ -3582,6 +3572,17 @@ namespace tools return false; } + if (!req.language.empty()) + { + if (!crypto::ElectrumWords::is_valid_language(req.language)) + { + er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; + er.message = "The specified seed language is invalid."; + return false; + } + wal->set_seed_language(req.language); + } + // set blockheight if given try { @@ -3725,12 +3726,7 @@ namespace tools er.message = "Wallet was using the old seed language. You need to specify a new seed language."; return false; } - std::vector<std::string> language_list; - std::vector<std::string> language_list_en; - crypto::ElectrumWords::get_language_list(language_list); - crypto::ElectrumWords::get_language_list(language_list_en, true); - if (std::find(language_list.begin(), language_list.end(), req.language) == language_list.end() && - std::find(language_list_en.begin(), language_list_en.end(), req.language) == language_list_en.end()) + if (!crypto::ElectrumWords::is_valid_language(req.language)) { er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; er.message = "Wallet was using the old seed language, and the specified new seed language is invalid."; diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index abc7702f7..0002508a2 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -2214,6 +2214,7 @@ namespace wallet_rpc std::string viewkey; std::string password; bool autosave_current; + std::string language; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE_OPT(restore_height, (uint64_t)0) @@ -2223,6 +2224,7 @@ namespace wallet_rpc KV_SERIALIZE(viewkey) KV_SERIALIZE(password) KV_SERIALIZE_OPT(autosave_current, true) + KV_SERIALIZE(language) END_KV_SERIALIZE_MAP() }; |