diff options
56 files changed, 678 insertions, 550 deletions
@@ -385,6 +385,50 @@ If you want to help out, see CONTRIBUTING for a set of guidelines. This section contains general instructions for debugging failed installs or problems encountered with Monero. First ensure you are running the latest version built from the github repo. +## Obtaining Stack Traces and Core Dumps on Unix Systems + +We generally use the tool `gdb` (GNU debugger) to provide stack trace functionality, and `ulimit` to provide core dumps in builds which crash or segfault. + +* To use gdb in order to obtain a stack trace for a build that has stalled: + +Run the build. + +Once it stalls, enter the following command: + +``` +gdb /path/to/monerod `pidof monerod` +``` + +Type `thread apply all bt` within gdb in order to obtain the stack trace + +* If however the core dumps or segfaults: + +Enter `ulimit -c unlimited` on the command line to enable unlimited filesizes for core dumps + +Run the build. + +When it terminates with an output along the lines of "Segmentation fault (core dumped)", there should be a core dump file in the same directory as monerod. + +You can now analyse this core dump with `gdb` as follows: + +`gdb /path/to/monerod /path/to/dumpfile` + +Print the stack trace with `bt` + +* To run monero within gdb: + +Type `gdb /path/to/monerod` + +Pass command-line options with `--args` followed by the relevant arguments + +Type `run` to run monerod + +## Analysing Memory Corruption + +We use the tool `valgrind` for this. + +Run with `valgrind /path/to/monerod`. It will be slow. + ## LMDB Instructions for debugging suspected blockchain corruption as per @HYC diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h index a54318ebb..c5aeb9251 100644 --- a/contrib/epee/include/net/http_client.h +++ b/contrib/epee/include/net/http_client.h @@ -263,7 +263,6 @@ using namespace std; blocked_mode_client m_net_client; std::string m_host_buff; std::string m_port; - unsigned int m_timeout; std::string m_header_cache; http_response_info m_response_info; size_t m_len_in_summary; @@ -276,23 +275,43 @@ using namespace std; critical_section m_lock; public: - void set_host_name(const std::string& name) + explicit http_simple_client() + : i_target_handler() + , m_net_client() + , m_host_buff() + , m_port() + , m_header_cache() + , m_response_info() + , m_len_in_summary(0) + , m_len_in_remain(0) + , m_pcontent_encoding_handler(nullptr) + , m_state() + , m_chunked_state() + , m_chunked_cache() + , m_lock() + {} + + bool set_server(const std::string& address) + { + http::url_content parsed{}; + const bool r = parse_url(address, parsed); + CHECK_AND_ASSERT_MES(r, false, "failed to parse url: " << address); + set_server(std::move(parsed.host), std::to_string(parsed.port)); + return true; + } + + void set_server(std::string host, std::string port) { CRITICAL_REGION_LOCAL(m_lock); - m_host_buff = name; + disconnect(); + m_host_buff = std::move(host); + m_port = std::move(port); } - bool connect(const std::string& host, int port, unsigned int timeout) - { - return connect(host, std::to_string(port), timeout); - } - bool connect(const std::string& host, const std::string& port, unsigned int timeout) + + bool connect(std::chrono::milliseconds timeout) { CRITICAL_REGION_LOCAL(m_lock); - m_host_buff = host; - m_port = port; - m_timeout = timeout; - - return m_net_client.connect(host, port, timeout, timeout); + return m_net_client.connect(m_host_buff, m_port, timeout); } //--------------------------------------------------------------------------- bool disconnect() @@ -316,20 +335,20 @@ using namespace std; } //--------------------------------------------------------------------------- inline - bool invoke_get(const std::string& uri, const std::string& body = std::string(), const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) + bool invoke_get(const std::string& uri, std::chrono::milliseconds timeout, const std::string& body = std::string(), const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) { CRITICAL_REGION_LOCAL(m_lock); - return invoke(uri, "GET", body, ppresponse_info, additional_params); + return invoke(uri, "GET", body, timeout, ppresponse_info, additional_params); } //--------------------------------------------------------------------------- - inline bool invoke(const std::string& uri, const std::string& method, const std::string& body, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) + inline bool invoke(const std::string& uri, const std::string& method, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) { CRITICAL_REGION_LOCAL(m_lock); if(!is_connected()) { MDEBUG("Reconnecting..."); - if(!connect(m_host_buff, m_port, m_timeout)) + if(!connect(timeout)) { MDEBUG("Failed to connect to " << m_host_buff << ":" << m_port); return false; @@ -347,27 +366,27 @@ using namespace std; req_buff += "\r\n"; //-- - bool res = m_net_client.send(req_buff); + bool res = m_net_client.send(req_buff, timeout); CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND"); if(body.size()) - res = m_net_client.send(body); + res = m_net_client.send(body, timeout); CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND"); if(ppresponse_info) *ppresponse_info = &m_response_info; m_state = reciev_machine_state_header; - return handle_reciev(); + return handle_reciev(timeout); } //--------------------------------------------------------------------------- - inline bool invoke_post(const std::string& uri, const std::string& body, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) + inline bool invoke_post(const std::string& uri, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) { CRITICAL_REGION_LOCAL(m_lock); - return invoke(uri, "POST", body, ppresponse_info, additional_params); + return invoke(uri, "POST", body, timeout, ppresponse_info, additional_params); } private: //--------------------------------------------------------------------------- - inline bool handle_reciev() + inline bool handle_reciev(std::chrono::milliseconds timeout) { CRITICAL_REGION_LOCAL(m_lock); bool keep_handling = true; @@ -377,7 +396,7 @@ using namespace std; { if(need_more_data) { - if(!m_net_client.recv(recv_buffer)) + if(!m_net_client.recv(recv_buffer, timeout)) { MERROR("Unexpected recv fail"); m_state = reciev_machine_state_error; @@ -878,33 +897,6 @@ using namespace std; return true; } }; - - - - /************************************************************************/ - /* */ - /************************************************************************/ - //inline - template<class t_transport> - bool invoke_request(const std::string& url, t_transport& tr, unsigned int timeout, const http_response_info** ppresponse_info, const std::string& method = "GET", const std::string& body = std::string(), const fields_list& additional_params = fields_list()) - { - http::url_content u_c; - bool res = parse_url(url, u_c); - - if(!tr.is_connected() && !u_c.host.empty()) - { - CHECK_AND_ASSERT_MES(res, false, "failed to parse url: " << url); - - if(!u_c.port) - u_c.port = 80;//default for http - - res = tr.connect(u_c.host, static_cast<int>(u_c.port), timeout); - CHECK_AND_ASSERT_MES(res, false, "failed to connect " << u_c.host << ":" << u_c.port); - } - - return tr.invoke(u_c.uri, method, body, ppresponse_info, additional_params); - } - } } } diff --git a/contrib/epee/include/net/http_client_abstract_invoke.h b/contrib/epee/include/net/http_client_abstract_invoke.h deleted file mode 100644 index 9b6ab4db8..000000000 --- a/contrib/epee/include/net/http_client_abstract_invoke.h +++ /dev/null @@ -1,101 +0,0 @@ - -// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of the Andrey N. Sabelnikov 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 OWNER BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// - -#pragma once -#include "storages/serializeble_struct_helper.h" - -#undef MONERO_DEFAULT_LOG_CATEGORY -#define MONERO_DEFAULT_LOG_CATEGORY "net.http" - -namespace epee -{ - namespace net_utils - { - namespace http - { - template<class TArg, class TResult, class TTransport> - bool invoke_http_json_remote_command(const std::string& url, TArg& out_struct, TResult& result_struct, TTransport& transport, unsigned int timeout = 5000, const std::string& method = "GET") - { - std::string req_param; - StorageNamed::InMemStorageSpace::json::store_t_to_json(out_struct, req_param); - - const http_response_info* pri = NULL; - if(!invoke_request(url, transport, timeout, &pri, method, req_param)) - { - LOG_PRINT_L1("Failed to invoke http request to " << url); - return false; - } - - if(!pri->m_response_code) - { - LOG_PRINT_L1("Failed to invoke http request to " << url << ", internal error (null response ptr)"); - return false; - } - - if(pri->m_response_code != 200) - { - LOG_PRINT_L1("Failed to invoke http request to " << url << ", wrong response code: " << pri->m_response_code); - return false; - } - - return StorageNamed::InMemStorageSpace::json::load_t_from_json(result_struct, pri->m_body); - } - - - - template<class TArg, class TResult, class TTransport> - bool invoke_http_bin_remote_command(const std::string& url, TArg& out_struct, TResult& result_struct, TTransport& transport, unsigned int timeout = 5000, const std::string& method = "GET") - { - std::string req_param; - epee::StorageNamed::save_struct_as_storage_to_buff(out_struct, req_param); - - const http_response_info* pri = NULL; - if(!invoke_request(url, transport, timeout, &pri, method, req_param)) - { - LOG_PRINT_L1("Failed to invoke http request to " << url); - return false; - } - - if(!pri->m_response_code) - { - LOG_PRINT_L1("Failed to invoke http request to " << url << ", internal error (null response ptr)"); - return false; - } - - if(pri->m_response_code != 200) - { - LOG_PRINT_L1("Failed to invoke http request to " << url << ", wrong response code: " << pri->m_response_code); - return false; - } - - return epee::StorageNamed::load_struct_from_storage_buff(result_struct, pri->m_body); - } - - - } - } -} diff --git a/contrib/epee/include/net/net_helper.h b/contrib/epee/include/net/net_helper.h index 22cea122f..432169990 100644 --- a/contrib/epee/include/net/net_helper.h +++ b/contrib/epee/include/net/net_helper.h @@ -37,6 +37,7 @@ #include <ostream> #include <string> #include <boost/asio.hpp> +#include <boost/asio/steady_timer.hpp> #include <boost/preprocessor/selection/min.hpp> #include <boost/lambda/bind.hpp> #include <boost/lambda/lambda.hpp> @@ -98,7 +99,7 @@ namespace net_utils // No deadline is required until the first socket operation is started. We // set the deadline to positive infinity so that the actor takes no action // until a specific deadline is set. - m_deadline.expires_at(boost::posix_time::pos_infin); + m_deadline.expires_at(std::chrono::steady_clock::time_point::max()); // Start the persistent actor that checks for deadline expiry. check_deadline(); @@ -111,26 +112,16 @@ namespace net_utils shutdown(); } - inline void set_recv_timeout(int reciev_timeout) - { - m_reciev_timeout = reciev_timeout; - } - inline - bool connect(const std::string& addr, int port, unsigned int connect_timeout, unsigned int reciev_timeout, const std::string& bind_ip = "0.0.0.0") + bool connect(const std::string& addr, int port, std::chrono::milliseconds timeout, const std::string& bind_ip = "0.0.0.0") { - return connect(addr, std::to_string(port), connect_timeout, reciev_timeout, bind_ip); + return connect(addr, std::to_string(port), timeout, bind_ip); } inline - bool connect(const std::string& addr, const std::string& port, unsigned int connect_timeout, unsigned int reciev_timeout, const std::string& bind_ip = "0.0.0.0") + bool connect(const std::string& addr, const std::string& port, std::chrono::milliseconds timeout, const std::string& bind_ip = "0.0.0.0") { - m_connect_timeout = connect_timeout; - m_reciev_timeout = reciev_timeout; m_connected = false; - if(!m_reciev_timeout) - m_reciev_timeout = m_connect_timeout; - try { m_socket.close(); @@ -164,7 +155,7 @@ namespace net_utils } - m_deadline.expires_from_now(boost::posix_time::milliseconds(m_connect_timeout)); + m_deadline.expires_from_now(timeout); boost::system::error_code ec = boost::asio::error::would_block; @@ -179,7 +170,7 @@ namespace net_utils if (!ec && m_socket.is_open()) { m_connected = true; - m_deadline.expires_at(boost::posix_time::pos_infin); + m_deadline.expires_at(std::chrono::steady_clock::time_point::max()); return true; }else { @@ -231,12 +222,12 @@ namespace net_utils inline - bool send(const std::string& buff) + bool send(const std::string& buff, std::chrono::milliseconds timeout) { try { - m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); + m_deadline.expires_from_now(timeout); // Set up the variable that receives the result of the asynchronous // operation. The error code is set to would_block to signal that the @@ -264,7 +255,7 @@ namespace net_utils return false; }else { - m_deadline.expires_at(boost::posix_time::pos_infin); + m_deadline.expires_at(std::chrono::steady_clock::time_point::max()); } } @@ -322,7 +313,7 @@ namespace net_utils return false; }else { - m_deadline.expires_at(boost::posix_time::pos_infin); + m_deadline.expires_at(std::chrono::steady_clock::time_point::max()); } } @@ -350,7 +341,7 @@ namespace net_utils } inline - bool recv(std::string& buff) + bool recv(std::string& buff, std::chrono::milliseconds timeout) { try @@ -358,7 +349,7 @@ namespace net_utils // Set a deadline for the asynchronous operation. Since this function uses // a composed operation (async_read_until), the deadline applies to the // entire operation, rather than individual reads from the socket. - m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); + m_deadline.expires_from_now(timeout); // Set up the variable that receives the result of the asynchronous // operation. The error code is set to would_block to signal that the @@ -404,7 +395,7 @@ namespace net_utils }else { MTRACE("READ ENDS: Success. bytes_tr: " << bytes_transfered); - m_deadline.expires_at(boost::posix_time::pos_infin); + m_deadline.expires_at(std::chrono::steady_clock::time_point::max()); } /*if(!bytes_transfered) @@ -432,7 +423,7 @@ namespace net_utils } - inline bool recv_n(std::string& buff, int64_t sz) + inline bool recv_n(std::string& buff, int64_t sz, std::chrono::milliseconds timeout) { try @@ -440,7 +431,7 @@ namespace net_utils // Set a deadline for the asynchronous operation. Since this function uses // a composed operation (async_read_until), the deadline applies to the // entire operation, rather than individual reads from the socket. - m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); + m_deadline.expires_from_now(timeout); // Set up the variable that receives the result of the asynchronous // operation. The error code is set to would_block to signal that the @@ -477,7 +468,7 @@ namespace net_utils return false; }else { - m_deadline.expires_at(boost::posix_time::pos_infin); + m_deadline.expires_at(std::chrono::steady_clock::time_point::max()); } if(bytes_transfered != buff.size()) @@ -539,7 +530,7 @@ namespace net_utils // Check whether the deadline has passed. We compare the deadline against // the current time since a new asynchronous operation may have moved the // deadline before this actor had a chance to run. - if (m_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now()) + if (m_deadline.expires_at() <= std::chrono::steady_clock::now()) { // The deadline has passed. The socket is closed so that any outstanding // asynchronous operations are cancelled. This allows the blocked @@ -550,7 +541,7 @@ namespace net_utils // There is no longer an active deadline. The expiry is set to positive // infinity so that the actor takes no action until a new deadline is set. - m_deadline.expires_at(boost::posix_time::pos_infin); + m_deadline.expires_at(std::chrono::steady_clock::time_point::max()); } // Put the actor back to sleep. @@ -562,11 +553,9 @@ namespace net_utils protected: boost::asio::io_service m_io_service; boost::asio::ip::tcp::socket m_socket; - int m_connect_timeout; - int m_reciev_timeout; bool m_initialized; bool m_connected; - boost::asio::deadline_timer m_deadline; + boost::asio::steady_timer m_deadline; volatile uint32_t m_shutdowned; }; diff --git a/contrib/epee/include/storages/http_abstract_invoke.h b/contrib/epee/include/storages/http_abstract_invoke.h index 00ee8a4ad..36177c7e0 100644 --- a/contrib/epee/include/storages/http_abstract_invoke.h +++ b/contrib/epee/include/storages/http_abstract_invoke.h @@ -35,28 +35,28 @@ namespace epee namespace net_utils { template<class t_request, class t_response, class t_transport> - bool invoke_http_json_remote_command2(const std::string& url, t_request& out_struct, t_response& result_struct, t_transport& transport, unsigned int timeout = 5000, const std::string& method = "GET") + bool invoke_http_json(const std::string& uri, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(5), const std::string& method = "GET") { std::string req_param; if(!serialization::store_t_to_json(out_struct, req_param)) return false; const http::http_response_info* pri = NULL; - if(!invoke_request(url, transport, timeout, &pri, method, req_param)) + if(!transport.invoke(uri, method, req_param, timeout, std::addressof(pri))) { - LOG_PRINT_L1("Failed to invoke http request to " << url); + LOG_PRINT_L1("Failed to invoke http request to " << uri); return false; } - if(!pri->m_response_code) + if(!pri) { - LOG_PRINT_L1("Failed to invoke http request to " << url << ", internal error (null response ptr)"); + LOG_PRINT_L1("Failed to invoke http request to " << uri << ", internal error (null response ptr)"); return false; } if(pri->m_response_code != 200) { - LOG_PRINT_L1("Failed to invoke http request to " << url << ", wrong response code: " << pri->m_response_code); + LOG_PRINT_L1("Failed to invoke http request to " << uri << ", wrong response code: " << pri->m_response_code); return false; } @@ -66,28 +66,28 @@ namespace epee template<class t_request, class t_response, class t_transport> - bool invoke_http_bin_remote_command2(const std::string& url, t_request& out_struct, t_response& result_struct, t_transport& transport, unsigned int timeout = 5000, const std::string& method = "GET") + bool invoke_http_bin(const std::string& uri, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(5), const std::string& method = "GET") { std::string req_param; if(!serialization::store_t_to_binary(out_struct, req_param)) return false; const http::http_response_info* pri = NULL; - if(!invoke_request(url, transport, timeout, &pri, method, req_param)) + if(!transport.invoke(uri, method, req_param, timeout, std::addressof(pri))) { - LOG_PRINT_L1("Failed to invoke http request to " << url); + LOG_PRINT_L1("Failed to invoke http request to " << uri); return false; } - if(!pri->m_response_code) + if(!pri) { - LOG_PRINT_L1("Failed to invoke http request to " << url << ", internal error (null response ptr)"); + LOG_PRINT_L1("Failed to invoke http request to " << uri << ", internal error (null response ptr)"); return false; } if(pri->m_response_code != 200) { - LOG_PRINT_L1("Failed to invoke http request to " << url << ", wrong response code: " << pri->m_response_code); + LOG_PRINT_L1("Failed to invoke http request to " << uri << ", wrong response code: " << pri->m_response_code); return false; } @@ -95,15 +95,15 @@ namespace epee } template<class t_request, class t_response, class t_transport> - bool invoke_http_json_rpc(const std::string& url, const std::string& method_name, t_request& out_struct, t_response& result_struct, t_transport& transport, unsigned int timeout = 5000, const std::string& http_method = "GET", const std::string& req_id = "0") + bool invoke_http_json_rpc(const std::string& uri, std::string method_name, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(5), const std::string& http_method = "GET", const std::string& req_id = "0") { epee::json_rpc::request<t_request> req_t = AUTO_VAL_INIT(req_t); req_t.jsonrpc = "2.0"; req_t.id = req_id; - req_t.method = method_name; + req_t.method = std::move(method_name); req_t.params = out_struct; epee::json_rpc::response<t_response, epee::json_rpc::error> resp_t = AUTO_VAL_INIT(resp_t); - if(!epee::net_utils::invoke_http_json_remote_command2(url, req_t, resp_t, transport, timeout, http_method)) + if(!epee::net_utils::invoke_http_json(uri, req_t, resp_t, transport, timeout, http_method)) { return false; } @@ -117,9 +117,9 @@ namespace epee } template<class t_command, class t_transport> - bool invoke_http_json_rpc(const std::string& url, typename t_command::request& out_struct, typename t_command::response& result_struct, t_transport& transport, unsigned int timeout = 5000, const std::string& http_method = "GET", const std::string& req_id = "0") + bool invoke_http_json_rpc(const std::string& uri, typename t_command::request& out_struct, typename t_command::response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(5), const std::string& http_method = "GET", const std::string& req_id = "0") { - return invoke_http_json_rpc(url, t_command::methodname(), out_struct, result_struct, transport, timeout, http_method, req_id); + return invoke_http_json_rpc(uri, t_command::methodname(), out_struct, result_struct, transport, timeout, http_method, req_id); } } diff --git a/contrib/epee/src/CMakeLists.txt b/contrib/epee/src/CMakeLists.txt index 8bc512893..93c9a94f7 100644 --- a/contrib/epee/src/CMakeLists.txt +++ b/contrib/epee/src/CMakeLists.txt @@ -27,3 +27,13 @@ # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. add_library(epee STATIC http_auth.cpp mlog.cpp) +# Build and install libepee if we're building for GUI +if (BUILD_GUI_DEPS) + if(IOS) + set(lib_folder lib-${ARCH}) + else() + set(lib_folder lib) + endif() + install(TARGETS epee + ARCHIVE DESTINATION ${lib_folder}) +endif()
\ No newline at end of file diff --git a/external/db_drivers/liblmdb/mdb.c b/external/db_drivers/liblmdb/mdb.c index 32e225163..d778037b0 100644 --- a/external/db_drivers/liblmdb/mdb.c +++ b/external/db_drivers/liblmdb/mdb.c @@ -1953,13 +1953,15 @@ static void mdb_cursor_unref(MDB_cursor *mc) { int i; - if (!mc->mc_snum || !mc->mc_pg[0] || IS_SUBP(mc->mc_pg[0])) - return; - for (i=0; i<mc->mc_snum; i++) - mdb_page_unref(mc->mc_txn, mc->mc_pg[i]); - if (mc->mc_ovpg) { - mdb_page_unref(mc->mc_txn, mc->mc_ovpg); - mc->mc_ovpg = 0; + if (mc->mc_txn->mt_rpages[0].mid) { + if (!mc->mc_snum || !mc->mc_pg[0] || IS_SUBP(mc->mc_pg[0])) + return; + for (i=0; i<mc->mc_snum; i++) + mdb_page_unref(mc->mc_txn, mc->mc_pg[i]); + if (mc->mc_ovpg) { + mdb_page_unref(mc->mc_txn, mc->mc_ovpg); + mc->mc_ovpg = 0; + } } mc->mc_snum = mc->mc_top = 0; mc->mc_pg[0] = NULL; diff --git a/external/easylogging++/easylogging++.h b/external/easylogging++/easylogging++.h index 3395c2cb2..d28152667 100644 --- a/external/easylogging++/easylogging++.h +++ b/external/easylogging++/easylogging++.h @@ -1104,8 +1104,8 @@ namespace el { ELPP_UNUSED(ms); # endif // ELPP_ASYNC_LOGGING } - typedef std::mutex Mutex; - typedef std::lock_guard<std::mutex> ScopedLock; + typedef std::recursive_mutex Mutex; + typedef std::lock_guard<std::recursive_mutex> ScopedLock; # endif // !ELPP_USE_STD_THREADING #else namespace internal { diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 7d548afed..1cfcf3a9e 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -1056,10 +1056,11 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags) // check for existing LMDB files in base directory boost::filesystem::path old_files = direc.parent_path(); - if (boost::filesystem::exists(old_files / "data.mdb") || boost::filesystem::exists(old_files / "lock.mdb")) + if (boost::filesystem::exists(old_files / CRYPTONOTE_BLOCKCHAINDATA_FILENAME) + || boost::filesystem::exists(old_files / CRYPTONOTE_BLOCKCHAINDATA_LOCK_FILENAME)) { LOG_PRINT_L0("Found existing LMDB files in " << old_files.string()); - LOG_PRINT_L0("Move data.mdb and/or lock.mdb to " << filename << ", or delete them, and then restart"); + LOG_PRINT_L0("Move " << CRYPTONOTE_BLOCKCHAINDATA_FILENAME << " and/or " << CRYPTONOTE_BLOCKCHAINDATA_LOCK_FILENAME << " to " << filename << ", or delete them, and then restart"); throw DB_ERROR("Database could not be opened"); } @@ -1313,9 +1314,9 @@ std::vector<std::string> BlockchainLMDB::get_filenames() const std::vector<std::string> filenames; boost::filesystem::path datafile(m_folder); - datafile /= "data.mdb"; + datafile /= CRYPTONOTE_BLOCKCHAINDATA_FILENAME; boost::filesystem::path lockfile(m_folder); - lockfile /= "lock.mdb"; + lockfile /= CRYPTONOTE_BLOCKCHAINDATA_LOCK_FILENAME; filenames.push_back(datafile.string()); filenames.push_back(lockfile.string()); diff --git a/src/common/dns_utils.cpp b/src/common/dns_utils.cpp index 2efdcffcd..83259bc70 100644 --- a/src/common/dns_utils.cpp +++ b/src/common/dns_utils.cpp @@ -451,22 +451,6 @@ std::string get_account_address_as_str_from_url(const std::string& url, bool& dn return addresses[0]; } -bool get_account_address_from_str_or_url( - cryptonote::account_public_address& address - , bool& has_payment_id - , crypto::hash8& payment_id - , bool testnet - , const std::string& str_or_url - ) -{ - if (cryptonote::get_account_integrated_address_from_str(address, has_payment_id, payment_id, testnet, str_or_url)) - return true; - bool dnssec_valid; - std::string address_str = get_account_address_as_str_from_url(str_or_url, dnssec_valid); - return !address_str.empty() && - cryptonote::get_account_integrated_address_from_str(address, has_payment_id, payment_id, testnet, address_str); -} - } // namespace tools::dns_utils } // namespace tools diff --git a/src/common/dns_utils.h b/src/common/dns_utils.h index 5fe1d4775..8a63a8129 100644 --- a/src/common/dns_utils.h +++ b/src/common/dns_utils.h @@ -164,13 +164,6 @@ std::string address_from_txt_record(const std::string& s); std::vector<std::string> addresses_from_url(const std::string& url, bool& dnssec_valid); std::string get_account_address_as_str_from_url(const std::string& url, bool& dnssec_valid); -bool get_account_address_from_str_or_url( - cryptonote::account_public_address& address - , bool& has_payment_id - , crypto::hash8& payment_id - , bool testnet - , const std::string& str_or_url - ); } // namespace tools::dns_utils diff --git a/src/common/http_connection.h b/src/common/http_connection.h index 156474cdd..8a786361a 100644 --- a/src/common/http_connection.h +++ b/src/common/http_connection.h @@ -28,6 +28,7 @@ #pragma once +#include <chrono> #include "string_tools.h" #include "net/http_client.h" @@ -38,20 +39,16 @@ private: epee::net_utils::http::http_simple_client * mp_http_client; bool m_ok; public: - static unsigned int const TIMEOUT = 200000; + static constexpr std::chrono::seconds TIMEOUT() + { + return std::chrono::minutes(3) + std::chrono::seconds(30); + } - t_http_connection( - epee::net_utils::http::http_simple_client * p_http_client - , uint32_t ip - , uint16_t port - ) + t_http_connection(epee::net_utils::http::http_simple_client* p_http_client) : mp_http_client(p_http_client) , m_ok(false) { - // TODO fix http client so that it accepts properly typed arguments - std::string ip_str = epee::string_tools::get_ip_string_from_int32(ip); - std::string port_str = boost::lexical_cast<std::string>(port); - m_ok = mp_http_client->connect(ip_str, port_str, TIMEOUT); + m_ok = mp_http_client->connect(TIMEOUT()); } ~t_http_connection() diff --git a/src/common/rpc_client.h b/src/common/rpc_client.h index 9c0036198..f5ecc8b50 100644 --- a/src/common/rpc_client.h +++ b/src/common/rpc_client.h @@ -34,7 +34,6 @@ #include "storages/http_abstract_invoke.h" #include "net/http_client.h" #include "string_tools.h" -#include <boost/lexical_cast.hpp> namespace tools { @@ -42,27 +41,16 @@ namespace tools { private: epee::net_utils::http::http_simple_client m_http_client; - uint32_t m_ip; - uint16_t m_port; public: t_rpc_client( uint32_t ip , uint16_t port ) : m_http_client{} - , m_ip{ip} - , m_port{port} - {} - - std::string build_url(std::string const & relative_url) const { - std::string result = - "http://" - + epee::string_tools::get_ip_string_from_int32(m_ip) - + ":" - + boost::lexical_cast<std::string>(m_port) - + relative_url; - return result; + m_http_client.set_server( + epee::string_tools::get_ip_string_from_int32(ip), std::to_string(port) + ); } template <typename T_req, typename T_res> @@ -72,8 +60,7 @@ namespace tools , std::string const & method_name ) { - std::string rpc_url = build_url("/json_rpc"); - t_http_connection connection(&m_http_client, m_ip, m_port); + t_http_connection connection(&m_http_client); bool ok = connection.is_open(); if (!ok) @@ -81,7 +68,7 @@ namespace tools fail_msg_writer() << "Couldn't connect to daemon"; return false; } - ok = ok && epee::net_utils::invoke_http_json_rpc(rpc_url, method_name, req, res, m_http_client); + ok = ok && epee::net_utils::invoke_http_json_rpc("/json_rpc", method_name, req, res, m_http_client, t_http_connection::TIMEOUT()); if (!ok) { fail_msg_writer() << "Daemon request failed"; @@ -101,11 +88,10 @@ namespace tools , std::string const & fail_msg ) { - std::string rpc_url = build_url("/json_rpc"); - t_http_connection connection(&m_http_client, m_ip, m_port); + t_http_connection connection(&m_http_client); bool ok = connection.is_open(); - ok = ok && epee::net_utils::invoke_http_json_rpc(rpc_url, method_name, req, res, m_http_client); + ok = ok && epee::net_utils::invoke_http_json_rpc("/json_rpc", method_name, req, res, m_http_client, t_http_connection::TIMEOUT()); if (!ok) { fail_msg_writer() << "Couldn't connect to daemon"; @@ -130,11 +116,10 @@ namespace tools , std::string const & fail_msg ) { - std::string rpc_url = build_url(relative_url); - t_http_connection connection(&m_http_client, m_ip, m_port); + t_http_connection connection(&m_http_client); bool ok = connection.is_open(); - ok = ok && epee::net_utils::invoke_http_json_remote_command2(rpc_url, req, res, m_http_client); + ok = ok && epee::net_utils::invoke_http_json(relative_url, req, res, m_http_client, t_http_connection::TIMEOUT()); if (!ok) { fail_msg_writer() << "Couldn't connect to daemon"; @@ -153,7 +138,7 @@ namespace tools bool check_connection() { - t_http_connection connection(&m_http_client, m_ip, m_port); + t_http_connection connection(&m_http_client); return connection.is_open(); } }; diff --git a/src/common/unordered_containers_boost_serialization.h b/src/common/unordered_containers_boost_serialization.h index 08b5d9ccf..b2d5b27a6 100644 --- a/src/common/unordered_containers_boost_serialization.h +++ b/src/common/unordered_containers_boost_serialization.h @@ -43,7 +43,7 @@ namespace boost { size_t s = x.size(); a << s; - BOOST_FOREACH(auto& v, x) + for(auto& v: x) { a << v.first; a << v.second; @@ -72,7 +72,7 @@ namespace boost { size_t s = x.size(); a << s; - BOOST_FOREACH(auto& v, x) + for(auto& v: x) { a << v.first; a << v.second; @@ -101,7 +101,7 @@ namespace boost { size_t s = x.size(); a << s; - BOOST_FOREACH(auto& v, x) + for(auto& v: x) { a << v; } diff --git a/src/common/util.cpp b/src/common/util.cpp index 6dec6af2a..bfcf86bc6 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -35,6 +35,7 @@ using namespace epee; #include "util.h" #include "cryptonote_config.h" +#include "net/http_client.h" // epee::net_utils::... #ifdef WIN32 #include <windows.h> @@ -44,6 +45,7 @@ using namespace epee; #include <sys/utsname.h> #endif #include <boost/filesystem.hpp> +#include <boost/asio.hpp> namespace tools @@ -531,4 +533,39 @@ std::string get_nix_version_display_string() boost::lock_guard<boost::mutex> lock(max_concurrency_lock); return max_concurrency; } + + bool is_local_address(const std::string &address) + { + // extract host + epee::net_utils::http::url_content u_c; + if (!epee::net_utils::parse_url(address, u_c)) + { + MWARNING("Failed to determine whether address '" << address << "' is local, assuming not"); + return false; + } + if (u_c.host.empty()) + { + MWARNING("Failed to determine whether address '" << address << "' is local, assuming not"); + return false; + } + + // resolve to IP + boost::asio::io_service io_service; + boost::asio::ip::tcp::resolver resolver(io_service); + boost::asio::ip::tcp::resolver::query query(u_c.host, ""); + boost::asio::ip::tcp::resolver::iterator i = resolver.resolve(query); + while (i != boost::asio::ip::tcp::resolver::iterator()) + { + const boost::asio::ip::tcp::endpoint &ep = *i; + if (ep.address().is_loopback()) + { + MDEBUG("Address '" << address << "' is local"); + return true; + } + ++i; + } + + MDEBUG("Address '" << address << "' is not local"); + return false; + } } diff --git a/src/common/util.h b/src/common/util.h index 4437d821f..c2ffc44ca 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -181,4 +181,6 @@ namespace tools void set_max_concurrency(unsigned n); unsigned get_max_concurrency(); + + bool is_local_address(const std::string &address); } diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index 95cbf74f0..97f2f2afc 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -120,8 +120,8 @@ #define CRYPTONOTE_NAME "bitmonero" #define CRYPTONOTE_POOLDATA_FILENAME "poolstate.bin" -#define CRYPTONOTE_BLOCKCHAINDATA_FILENAME "blockchain.bin" -#define CRYPTONOTE_BLOCKCHAINDATA_TEMP_FILENAME "blockchain.bin.tmp" +#define CRYPTONOTE_BLOCKCHAINDATA_FILENAME "data.mdb" +#define CRYPTONOTE_BLOCKCHAINDATA_LOCK_FILENAME "lock.mdb" #define P2P_NET_DATA_FILENAME "p2pstate.bin" #define MINER_CONFIG_FILE_NAME "miner_conf.json" diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 789687ce0..b344c5597 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -31,6 +31,7 @@ #include <algorithm> #include <cstdio> #include <boost/filesystem.hpp> +#include <boost/range/adaptor/reversed.hpp> #include "include_base_utils.h" #include "cryptonote_basic_impl.h" @@ -933,7 +934,7 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std: size_t count = 0; size_t max_i = timestamps.size()-1; // get difficulties and timestamps from most recent blocks in alt chain - BOOST_REVERSE_FOREACH(auto it, alt_chain) + for(auto it: boost::adaptors::reverse(alt_chain)) { timestamps[max_i - count] = it->second.bl.timestamp; cumulative_difficulties[max_i - count] = it->second.cumulative_difficulty; diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index ca665e1d4..cd452faf4 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -36,7 +36,6 @@ #include <boost/multi_index/global_fun.hpp> #include <boost/multi_index/hashed_index.hpp> #include <boost/multi_index/member.hpp> -#include <boost/foreach.hpp> #include <atomic> #include <unordered_map> #include <unordered_set> diff --git a/src/cryptonote_core/cryptonote_basic_impl.cpp b/src/cryptonote_core/cryptonote_basic_impl.cpp index 5a8c61dd9..51c9269a5 100644 --- a/src/cryptonote_core/cryptonote_basic_impl.cpp +++ b/src/cryptonote_core/cryptonote_basic_impl.cpp @@ -41,6 +41,7 @@ using namespace epee; #include "common/base58.h" #include "crypto/hash.h" #include "common/int-util.h" +#include "common/dns_utils.h" #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "cn" @@ -291,7 +292,34 @@ namespace cryptonote { crypto::hash8 payment_id; return get_account_integrated_address_from_str(adr, has_payment_id, payment_id, testnet, str); } - + //-------------------------------------------------------------------------------- + bool get_account_address_from_str_or_url( + cryptonote::account_public_address& address + , bool& has_payment_id + , crypto::hash8& payment_id + , bool testnet + , const std::string& str_or_url + ) + { + if (get_account_integrated_address_from_str(address, has_payment_id, payment_id, testnet, str_or_url)) + return true; + bool dnssec_valid; + std::string address_str = tools::dns_utils::get_account_address_as_str_from_url(str_or_url, dnssec_valid); + return !address_str.empty() && + get_account_integrated_address_from_str(address, has_payment_id, payment_id, testnet, address_str); + } + //-------------------------------------------------------------------------------- + bool get_account_address_from_str_or_url( + cryptonote::account_public_address& address + , bool testnet + , const std::string& str_or_url + ) + { + bool has_payment_id; + crypto::hash8 payment_id; + return get_account_address_from_str_or_url(address, testnet, str_or_url); + } + //-------------------------------------------------------------------------------- bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b) { return cryptonote::get_transaction_hash(a) == cryptonote::get_transaction_hash(b); } diff --git a/src/cryptonote_core/cryptonote_basic_impl.h b/src/cryptonote_core/cryptonote_basic_impl.h index 147bc89ba..5703a7d75 100644 --- a/src/cryptonote_core/cryptonote_basic_impl.h +++ b/src/cryptonote_core/cryptonote_basic_impl.h @@ -100,6 +100,20 @@ namespace cryptonote { , const std::string& str ); + bool get_account_address_from_str_or_url( + cryptonote::account_public_address& address + , bool& has_payment_id + , crypto::hash8& payment_id + , bool testnet + , const std::string& str_or_url + ); + + bool get_account_address_from_str_or_url( + cryptonote::account_public_address& address + , bool testnet + , const std::string& str_or_url + ); + bool is_coinbase(const transaction& tx); bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b); diff --git a/src/cryptonote_core/cryptonote_boost_serialization.h b/src/cryptonote_core/cryptonote_boost_serialization.h index 7423b222a..409b9798c 100644 --- a/src/cryptonote_core/cryptonote_boost_serialization.h +++ b/src/cryptonote_core/cryptonote_boost_serialization.h @@ -35,7 +35,6 @@ #include <boost/serialization/variant.hpp> #include <boost/serialization/set.hpp> #include <boost/serialization/map.hpp> -#include <boost/foreach.hpp> #include <boost/serialization/is_bitwise_serializable.hpp> #include <boost/archive/binary_iarchive.hpp> #include <boost/archive/portable_binary_iarchive.hpp> diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 09184a961..900dc58ba 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -31,7 +31,6 @@ #include "include_base_utils.h" using namespace epee; -#include <boost/foreach.hpp> #include <unordered_set> #include "cryptonote_core.h" #include "common/command_line.h" @@ -542,6 +541,7 @@ namespace cryptonote if (rv.outPk.size() != tx.vout.size()) { LOG_PRINT_L1("WRONG TRANSACTION BLOB, Bad outPk size in tx " << tx_hash << ", rejected"); + tvc.m_verifivation_failed = true; return false; } for (size_t n = 0; n < tx.rct_signatures.outPk.size(); ++n) @@ -678,7 +678,7 @@ namespace cryptonote bool core::are_key_images_spent(const std::vector<crypto::key_image>& key_im, std::vector<bool> &spent) const { spent.clear(); - BOOST_FOREACH(auto& ki, key_im) + for(auto& ki: key_im) { spent.push_back(m_blockchain_storage.have_tx_keyimg_as_spent(ki)); } @@ -691,14 +691,14 @@ namespace cryptonote uint64_t emission_amount = 0; uint64_t total_fee_amount = 0; this->get_blocks(start_offset, count, blocks); - BOOST_FOREACH(auto& b, blocks) + for(auto& b: blocks) { std::list<transaction> txs; std::list<crypto::hash> missed_txs; uint64_t coinbase_amount = get_outs_money_amount(b.miner_tx); this->get_transactions(b.tx_hashes, txs, missed_txs); uint64_t tx_fee_amount = 0; - BOOST_FOREACH(const auto& tx, txs) + for(const auto& tx: txs) { tx_fee_amount += get_tx_fee(tx); } @@ -713,7 +713,7 @@ namespace cryptonote bool core::check_tx_inputs_keyimages_diff(const transaction& tx) const { std::unordered_set<crypto::key_image> ki; - BOOST_FOREACH(const auto& in, tx.vin) + for(const auto& in: tx.vin) { CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false); if(!ki.insert(tokey_in.k_image).second) @@ -879,7 +879,7 @@ namespace cryptonote block_to_blob(b, arg.b.block); //pack transactions - BOOST_FOREACH(auto& tx, txs) + for(auto& tx: txs) arg.b.txs.push_back(t_serializable_object_to_blob(tx)); m_pprotocol->relay_block(arg, exclude_context); diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index e04409d87..70ba7ee18 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -32,7 +32,6 @@ using namespace epee; #include "cryptonote_format_utils.h" -#include <boost/foreach.hpp> #include "cryptonote_config.h" #include "miner.h" #include "crypto/crypto.h" @@ -274,12 +273,12 @@ namespace cryptonote } uint64_t amount_in = 0; uint64_t amount_out = 0; - BOOST_FOREACH(auto& in, tx.vin) + for(auto& in: tx.vin) { CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key), 0, "unexpected type id in transaction"); amount_in += boost::get<txin_to_key>(in).amount; } - BOOST_FOREACH(auto& o, tx.vout) + for(auto& o: tx.vout) amount_out += o.amount; CHECK_AND_ASSERT_MES(amount_in >= amount_out, false, "transaction spend (" <<amount_in << ") more than it has (" << amount_out << ")"); @@ -540,7 +539,7 @@ namespace cryptonote uint64_t summary_inputs_money = 0; //fill inputs int idx = -1; - BOOST_FOREACH(const tx_source_entry& src_entr, sources) + for(const tx_source_entry& src_entr: sources) { ++idx; if(src_entr.real_output >= src_entr.outputs.size()) @@ -574,7 +573,7 @@ namespace cryptonote input_to_key.k_image = img; //fill outputs array and use relative offsets - BOOST_FOREACH(const tx_source_entry::output_entry& out_entry, src_entr.outputs) + for(const tx_source_entry::output_entry& out_entry: src_entr.outputs) input_to_key.key_offsets.push_back(out_entry.first); input_to_key.key_offsets = absolute_output_offsets_to_relative(input_to_key.key_offsets); @@ -588,7 +587,7 @@ namespace cryptonote uint64_t summary_outs_money = 0; //fill outputs size_t output_index = 0; - BOOST_FOREACH(const tx_destination_entry& dst_entr, shuffled_dsts) + for(const tx_destination_entry& dst_entr: shuffled_dsts) { CHECK_AND_ASSERT_MES(dst_entr.amount > 0 || tx.version > 1, false, "Destination with wrong amount: " << dst_entr.amount); crypto::key_derivation derivation; @@ -639,13 +638,13 @@ namespace cryptonote std::stringstream ss_ring_s; size_t i = 0; - BOOST_FOREACH(const tx_source_entry& src_entr, sources) + for(const tx_source_entry& src_entr: sources) { ss_ring_s << "pub_keys:" << ENDL; std::vector<const crypto::public_key*> keys_ptrs; std::vector<crypto::public_key> keys(src_entr.outputs.size()); size_t ii = 0; - BOOST_FOREACH(const tx_source_entry::output_entry& o, src_entr.outputs) + for(const tx_source_entry::output_entry& o: src_entr.outputs) { keys[ii] = rct2pk(o.second.dest); keys_ptrs.push_back(&keys[ii]); @@ -677,7 +676,7 @@ namespace cryptonote if (!use_simple_rct) { // non simple ringct requires all real inputs to be at the same index for all inputs - BOOST_FOREACH(const tx_source_entry& src_entr, sources) + for(const tx_source_entry& src_entr: sources) { if(src_entr.real_output != sources.begin()->real_output) { @@ -784,7 +783,7 @@ namespace cryptonote bool get_inputs_money_amount(const transaction& tx, uint64_t& money) { money = 0; - BOOST_FOREACH(const auto& in, tx.vin) + for(const auto& in: tx.vin) { CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false); money += tokey_in.amount; @@ -801,7 +800,7 @@ namespace cryptonote //--------------------------------------------------------------- bool check_inputs_types_supported(const transaction& tx) { - BOOST_FOREACH(const auto& in, tx.vin) + for(const auto& in: tx.vin) { CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key), false, "wrong variant type: " << in.type().name() << ", expected " << typeid(txin_to_key).name() @@ -813,7 +812,7 @@ namespace cryptonote //----------------------------------------------------------------------------------------------- bool check_outs_valid(const transaction& tx) { - BOOST_FOREACH(const tx_out& out, tx.vout) + for(const tx_out& out: tx.vout) { CHECK_AND_ASSERT_MES(out.target.type() == typeid(txout_to_key), false, "wrong variant type: " << out.target.type().name() << ", expected " << typeid(txout_to_key).name() @@ -838,7 +837,7 @@ namespace cryptonote bool check_inputs_overflow(const transaction& tx) { uint64_t money = 0; - BOOST_FOREACH(const auto& in, tx.vin) + for(const auto& in: tx.vin) { CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false); if(money > tokey_in.amount + money) @@ -851,7 +850,7 @@ namespace cryptonote bool check_outs_overflow(const transaction& tx) { uint64_t money = 0; - BOOST_FOREACH(const auto& o, tx.vout) + for(const auto& o: tx.vout) { if(money > o.amount + money) return false; @@ -863,7 +862,7 @@ namespace cryptonote uint64_t get_outs_money_amount(const transaction& tx) { uint64_t outputs_amount = 0; - BOOST_FOREACH(const auto& o, tx.vout) + for(const auto& o: tx.vout) outputs_amount += o.amount; return outputs_amount; } @@ -905,7 +904,7 @@ namespace cryptonote { money_transfered = 0; size_t i = 0; - BOOST_FOREACH(const tx_out& o, tx.vout) + for(const tx_out& o: tx.vout) { CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key), false, "wrong type id in transaction out" ); if(is_out_to_acc(acc, boost::get<txout_to_key>(o.target), tx_pub_key, i)) @@ -1177,7 +1176,7 @@ namespace cryptonote size_t bl_sz = 0; get_transaction_hash(b.miner_tx, h, bl_sz); txs_ids.push_back(h); - BOOST_FOREACH(auto& th, b.tx_hashes) + for(auto& th: b.tx_hashes) txs_ids.push_back(th); return get_tx_tree_hash(txs_ids); } diff --git a/src/cryptonote_core/miner.cpp b/src/cryptonote_core/miner.cpp index 51f508858..88c631f80 100644 --- a/src/cryptonote_core/miner.cpp +++ b/src/cryptonote_core/miner.cpp @@ -33,7 +33,6 @@ #include <boost/utility/value_init.hpp> #include <boost/interprocess/detail/atomic.hpp> #include <boost/limits.hpp> -#include <boost/foreach.hpp> #include "misc_language.h" #include "include_base_utils.h" #include "cryptonote_basic_impl.h" @@ -292,7 +291,7 @@ namespace cryptonote send_stop_signal(); CRITICAL_REGION_LOCAL(m_threads_lock); - BOOST_FOREACH(boost::thread& th, m_threads) + for(boost::thread& th: m_threads) th.join(); MINFO("Mining has been stopped, " << m_threads.size() << " finished" ); diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 6ad139023..e37ddec0d 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -63,7 +63,7 @@ namespace cryptonote size_t const TRANSACTION_SIZE_LIMIT_V2 = (((CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 125) / 100) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE); time_t const MIN_RELAY_TIME = (60 * 5); // only start re-relaying transactions after that many seconds time_t const MAX_RELAY_TIME = (60 * 60 * 4); // at most that many seconds between resends - float const ACCEPT_THRESHOLD = 0.99f; + float const ACCEPT_THRESHOLD = 1.0f; // a kind of increasing backoff within min/max bounds time_t get_relay_delay(time_t now, time_t received) @@ -240,7 +240,7 @@ namespace cryptonote // assume failure during verification steps until success is certain tvc.m_verifivation_failed = true; - BOOST_FOREACH(const auto& in, tx.vin) + for(const auto& in: tx.vin) { CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, txin, false); std::unordered_set<crypto::hash>& kei_image_set = m_spent_key_images[txin.k_image]; @@ -253,7 +253,7 @@ namespace cryptonote tvc.m_verifivation_failed = false; - m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>((double)blob_size / fee, receive_time), id); + m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)blob_size, receive_time), id); return true; } @@ -275,7 +275,7 @@ namespace cryptonote // ND: Speedup // 1. Move transaction hash calcuation outside of loop. ._. crypto::hash actual_hash = get_transaction_hash(tx); - BOOST_FOREACH(const txin_v& vi, tx.vin) + for(const txin_v& vi: tx.vin) { CHECKED_GET_SPECIFIC_VARIANT(vi, const txin_to_key, txin, false); auto it = m_spent_key_images.find(txin.k_image); @@ -415,7 +415,7 @@ namespace cryptonote void tx_memory_pool::get_transactions(std::list<transaction>& txs) const { CRITICAL_REGION_LOCAL(m_transactions_lock); - BOOST_FOREACH(const auto& tx_vt, m_transactions) + for(const auto& tx_vt: m_transactions) txs.push_back(tx_vt.second.tx); } //------------------------------------------------------------------ @@ -488,7 +488,7 @@ namespace cryptonote bool tx_memory_pool::have_tx_keyimges_as_spent(const transaction& tx) const { CRITICAL_REGION_LOCAL(m_transactions_lock); - BOOST_FOREACH(const auto& in, tx.vin) + for(const auto& in: tx.vin) { CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, true);//should never fail if(have_tx_keyimg_as_spent(tokey_in.k_image)) @@ -613,6 +613,10 @@ namespace cryptonote uint64_t best_coinbase = 0; total_size = 0; fee = 0; + + //baseline empty block + get_block_reward(median_size, total_size, already_generated_coins, best_coinbase, version); + size_t max_total_size = 2 * median_size - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; std::unordered_set<crypto::key_image> k_images; @@ -641,7 +645,7 @@ namespace cryptonote sorted_it++; continue; } - uint64_t coinbase = block_reward + fee; + uint64_t coinbase = block_reward + fee + tx_it->second.fee; if (coinbase < template_accept_threshold(best_coinbase)) { LOG_PRINT_L2(" would decrease coinbase to " << print_money(coinbase)); @@ -728,7 +732,7 @@ namespace cryptonote // no need to store queue of sorted transactions, as it's easy to generate. for (const auto& tx : m_transactions) { - m_txs_by_fee_and_receive_time.emplace(std::pair<double, time_t>((double)tx.second.blob_size / tx.second.fee, tx.second.receive_time), tx.first); + m_txs_by_fee_and_receive_time.emplace(std::pair<double, time_t>(tx.second.fee / (double)tx.second.blob_size, tx.second.receive_time), tx.first); } // Ignore deserialization error diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler-base.cpp b/src/cryptonote_protocol/cryptonote_protocol_handler-base.cpp index 56b82ed15..09c202e79 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler-base.cpp +++ b/src/cryptonote_protocol/cryptonote_protocol_handler-base.cpp @@ -52,7 +52,6 @@ #include "../../contrib/epee/include/net/net_utils_base.h" #include "../../contrib/epee/include/misc_log_ex.h" #include <boost/lambda/bind.hpp> -#include <boost/foreach.hpp> #include <boost/lambda/lambda.hpp> #include <boost/uuid/random_generator.hpp> #include <boost/chrono.hpp> diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index 73e4fa72f..1309ff742 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -411,7 +411,7 @@ namespace cryptonote transaction tx; crypto::hash tx_hash; - BOOST_FOREACH(auto& tx_blob, arg.b.txs) + for(auto& tx_blob: arg.b.txs) { if(parse_and_validate_tx_from_blob(tx_blob, tx)) { @@ -527,7 +527,7 @@ namespace cryptonote } size_t tx_idx = 0; - BOOST_FOREACH(auto& tx_hash, new_block.tx_hashes) + for(auto& tx_hash: new_block.tx_hashes) { if(m_core.get_pool_transaction(tx_hash, tx)) { @@ -638,7 +638,7 @@ namespace cryptonote fluffy_response.current_blockchain_height = m_core.get_current_blockchain_height(); fluffy_response.hop = arg.hop; size_t local_txs_count = local_txs.size(); - BOOST_FOREACH(auto& tx_idx, arg.missing_tx_indices) + for(auto& tx_idx: arg.missing_tx_indices) { if(tx_idx < local_txs_count) { @@ -790,7 +790,7 @@ namespace cryptonote context.m_remote_blockchain_height = arg.current_blockchain_height; size_t count = 0; - BOOST_FOREACH(const block_complete_entry& block_entry, arg.blocks) + for(const block_complete_entry& block_entry: arg.blocks) { if (m_stopping) { @@ -859,7 +859,7 @@ namespace cryptonote uint64_t previous_height = m_core.get_current_blockchain_height(); m_core.prepare_handle_incoming_blocks(arg.blocks); - BOOST_FOREACH(const block_complete_entry& block_entry, arg.blocks) + for(const block_complete_entry& block_entry: arg.blocks) { if (m_stopping) { @@ -869,7 +869,7 @@ namespace cryptonote // process transactions TIME_MEASURE_START(transactions_process_time); - BOOST_FOREACH(auto& tx_blob, block_entry.txs) + for(auto& tx_blob: block_entry.txs) { tx_verification_context tvc = AUTO_VAL_INIT(tvc); m_core.handle_incoming_tx(tx_blob, tvc, true, true, false); @@ -1077,7 +1077,7 @@ namespace cryptonote m_p2p->drop_connection(context); } - BOOST_FOREACH(auto& bl_id, arg.m_block_ids) + for(auto& bl_id: arg.m_block_ids) { if(!m_core.have_block(bl_id)) context.m_needed_objects.push_back(bl_id); diff --git a/src/daemon/protocol.h b/src/daemon/protocol.h index bc2333659..5bcb83dcf 100644 --- a/src/daemon/protocol.h +++ b/src/daemon/protocol.h @@ -77,6 +77,7 @@ public: m_protocol.deinit(); m_protocol.set_p2p_endpoint(nullptr); MGINFO("Cryptonote protocol stopped successfully"); + tools::success_msg_writer() << "Daemon stopped successfully"; } catch (...) { LOG_ERROR("Failed to stop cryptonote protocol!"); } diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index 8558ebc17..2bcfd7a95 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -368,7 +368,7 @@ bool t_rpc_command_executor::show_status() { std::time_t uptime = std::time(nullptr) - ires.start_time; - tools::success_msg_writer() << boost::format("Height: %llu/%llu (%.1f%%) on %s, %s, net hash %s, v%u%s, %s, %u+%u connections, uptime %uh %um %us") + tools::success_msg_writer() << boost::format("Height: %llu/%llu (%.1f%%) on %s, %s, net hash %s, v%u%s, %s, %u+%u connections, uptime %ud %uh %um %us") % (unsigned long long)ires.height % (unsigned long long)(ires.target_height >= ires.height ? ires.target_height : ires.height) % get_sync_percentage(ires) @@ -378,9 +378,11 @@ bool t_rpc_command_executor::show_status() { % (unsigned)hfres.version % get_fork_extra_info(hfres.earliest_height, ires.height, ires.target) % (hfres.state == cryptonote::HardFork::Ready ? "up to date" : hfres.state == cryptonote::HardFork::UpdateNeeded ? "update needed" : "out of date, likely forked") - % (unsigned)ires.outgoing_connections_count % (unsigned)ires.incoming_connections_count - % (unsigned int)floor(uptime / 3600.0) - % (unsigned int)floor(fmod(uptime, 3600.0) / 60.0) + % (unsigned)ires.outgoing_connections_count + % (unsigned)ires.incoming_connections_count + % (unsigned int)floor(uptime / 60.0 / 60.0 / 24.0) + % (unsigned int)floor(fmod((uptime / 60.0 / 60.0), 24.0) + % (unsigned int)floor(fmod((uptime / 60.0), 60.0) % (unsigned int)fmod(uptime, 60.0) ; @@ -1451,6 +1453,7 @@ bool t_rpc_command_executor::print_blockchain_dynamic_stats(uint64_t nblocks) std::string fail_message = "Problem fetching info"; + fereq.grace_blocks = 0; if (m_is_rpc) { if (!m_rpc_client->rpc_request(ireq, ires, "/getinfo", fail_message.c_str())) diff --git a/src/p2p/connection_basic.cpp b/src/p2p/connection_basic.cpp index 80915e9a3..bdb239ca8 100644 --- a/src/p2p/connection_basic.cpp +++ b/src/p2p/connection_basic.cpp @@ -56,7 +56,6 @@ #include "../../contrib/epee/include/net/net_utils_base.h" #include "../../contrib/epee/include/misc_log_ex.h" #include <boost/lambda/bind.hpp> -#include <boost/foreach.hpp> #include <boost/lambda/lambda.hpp> #include <boost/uuid/random_generator.hpp> #include <boost/chrono.hpp> diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 40598fc0f..5ed96c00b 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -31,7 +31,6 @@ #pragma once #include <boost/thread.hpp> #include <boost/bind.hpp> -#include <boost/foreach.hpp> #include <boost/bimap.hpp> #include <boost/multi_index_container.hpp> #include <boost/multi_index/ordered_index.hpp> diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 2cda7cb8b..7ab6a4894 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -1187,7 +1187,7 @@ namespace nodetool time(&now); delta = now - local_time; - BOOST_FOREACH(peerlist_entry& be, local_peerlist) + for(peerlist_entry& be: local_peerlist) { if(be.last_seen > local_time) { @@ -1325,7 +1325,7 @@ namespace nodetool template<class t_payload_net_handler> bool node_server<t_payload_net_handler>::relay_notify_to_list(int command, const std::string& data_buff, const std::list<boost::uuids::uuid> &connections) { - BOOST_FOREACH(const auto& c_id, connections) + for(const auto& c_id: connections) { m_net_server.get_config_object().notify(command, data_buff, c_id); } diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h index 160206ed3..c73d6615d 100644 --- a/src/p2p/net_peerlist.h +++ b/src/p2p/net_peerlist.h @@ -33,7 +33,6 @@ #include <list> #include <set> #include <map> -#include <boost/foreach.hpp> //#include <boost/bimap.hpp> //#include <boost/bimap/multiset_of.hpp> #include <boost/archive/binary_iarchive.hpp> @@ -45,6 +44,7 @@ #include <boost/multi_index/ordered_index.hpp> #include <boost/multi_index/identity.hpp> #include <boost/multi_index/member.hpp> +#include <boost/range/adaptor/reversed.hpp> #include "syncobj.h" @@ -230,7 +230,7 @@ namespace nodetool bool peerlist_manager::merge_peerlist(const std::list<peerlist_entry>& outer_bs) { CRITICAL_REGION_LOCAL(m_peerlist_lock); - BOOST_FOREACH(const peerlist_entry& be, outer_bs) + for(const peerlist_entry& be: outer_bs) { append_with_peer_gray(be); } @@ -283,7 +283,7 @@ namespace nodetool CRITICAL_REGION_LOCAL(m_peerlist_lock); peers_indexed::index<by_time>::type& by_time_index=m_peers_white.get<by_time>(); uint32_t cnt = 0; - BOOST_REVERSE_FOREACH(const peers_indexed::value_type& vl, by_time_index) + for(const peers_indexed::value_type& vl: boost::adaptors::reverse(by_time_index)) { if(!vl.last_seen) continue; @@ -301,13 +301,13 @@ namespace nodetool { CRITICAL_REGION_LOCAL(m_peerlist_lock); peers_indexed::index<by_time>::type& by_time_index_gr=m_peers_gray.get<by_time>(); - BOOST_REVERSE_FOREACH(const peers_indexed::value_type& vl, by_time_index_gr) + for(const peers_indexed::value_type& vl: boost::adaptors::reverse(by_time_index_gr)) { pl_gray.push_back(vl); } peers_indexed::index<by_time>::type& by_time_index_wt=m_peers_white.get<by_time>(); - BOOST_REVERSE_FOREACH(const peers_indexed::value_type& vl, by_time_index_wt) + for(const peers_indexed::value_type& vl: boost::adaptors::reverse(by_time_index_wt)) { pl_white.push_back(vl); } diff --git a/src/p2p/network_throttle-detail.cpp b/src/p2p/network_throttle-detail.cpp index 9efaaf95a..d4fe356a9 100644 --- a/src/p2p/network_throttle-detail.cpp +++ b/src/p2p/network_throttle-detail.cpp @@ -54,7 +54,6 @@ #include "../../contrib/epee/include/net/net_utils_base.h" #include "../../contrib/epee/include/misc_log_ex.h" #include <boost/lambda/bind.hpp> -#include <boost/foreach.hpp> #include <boost/lambda/lambda.hpp> #include <boost/uuid/random_generator.hpp> #include <boost/chrono.hpp> diff --git a/src/p2p/network_throttle.hpp b/src/p2p/network_throttle.hpp index b954c5b3a..4f6cbe9cf 100644 --- a/src/p2p/network_throttle.hpp +++ b/src/p2p/network_throttle.hpp @@ -57,7 +57,6 @@ #include "../../contrib/epee/include/net/net_utils_base.h" #include "../../contrib/epee/include/misc_log_ex.h" #include <boost/lambda/bind.hpp> -#include <boost/foreach.hpp> #include <boost/lambda/lambda.hpp> #include <boost/uuid/random_generator.hpp> #include <boost/chrono.hpp> diff --git a/src/p2p/p2p_protocol_defs.h b/src/p2p/p2p_protocol_defs.h index ce1ee1449..6d6ac7b98 100644 --- a/src/p2p/p2p_protocol_defs.h +++ b/src/p2p/p2p_protocol_defs.h @@ -83,7 +83,7 @@ namespace nodetool time(&now_time); std::stringstream ss; ss << std::setfill ('0') << std::setw (8) << std::hex << std::noshowbase; - BOOST_FOREACH(const peerlist_entry& pe, pl) + for(const peerlist_entry& pe: pl) { ss << pe.id << "\t" << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << ":" << boost::lexical_cast<std::string>(pe.adr.port) << " \tlast_seen: " << epee::misc_utils::get_time_interval_string(now_time - pe.last_seen) << std::endl; } diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h index b1aa243b9..0c27745e1 100644 --- a/src/ringct/rctTypes.h +++ b/src/ringct/rctTypes.h @@ -40,11 +40,11 @@ #include <cinttypes> extern "C" { -#include "crypto/generic-ops.h" #include "crypto/crypto-ops.h" #include "crypto/random.h" #include "crypto/keccak.h" } +#include "crypto/generic-ops.h" #include "crypto/crypto.h" #include "serialization/serialization.h" diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 7d896e491..b2e8e6716 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -28,7 +28,6 @@ // // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers -#include <boost/foreach.hpp> #include "include_base_utils.h" using namespace epee; @@ -160,7 +159,7 @@ namespace cryptonote return false; } - BOOST_FOREACH(auto& b, bs) + for(auto& b: bs) { res.blocks.resize(res.blocks.size()+1); res.blocks.back().block = block_to_blob(b.first); @@ -173,7 +172,7 @@ namespace cryptonote return false; } size_t txidx = 0; - BOOST_FOREACH(auto& t, b.second) + for(auto& t: b.second) { res.blocks.back().txs.push_back(tx_to_blob(t)); res.output_indices.back().indices.push_back(COMMAND_RPC_GET_BLOCKS_FAST::tx_output_indices()); @@ -205,7 +204,7 @@ namespace cryptonote } catch (...) { - res.status = "Error retrieving block at height " + height; + res.status = "Error retrieving block at height " + std::to_string(height); return true; } std::list<transaction> txs; @@ -381,7 +380,7 @@ namespace cryptonote { CHECK_CORE_BUSY(); std::vector<crypto::hash> vh; - BOOST_FOREACH(const auto& tx_hex_str, req.txs_hashes) + for(const auto& tx_hex_str: req.txs_hashes) { blobdata b; if(!string_tools::parse_hexstr_to_binbuff(tx_hex_str, b)) @@ -433,7 +432,7 @@ namespace cryptonote std::list<std::string>::const_iterator txhi = req.txs_hashes.begin(); std::vector<crypto::hash>::const_iterator vhi = vh.begin(); - BOOST_FOREACH(auto& tx, txs) + for(auto& tx: txs) { res.txs.push_back(COMMAND_RPC_GET_TRANSACTIONS::entry()); COMMAND_RPC_GET_TRANSACTIONS::entry &e = res.txs.back(); @@ -471,7 +470,7 @@ namespace cryptonote } } - BOOST_FOREACH(const auto& miss_tx, missed_txs) + for(const auto& miss_tx: missed_txs) { res.missed_tx.push_back(string_tools::pod_to_hex(miss_tx)); } @@ -485,7 +484,7 @@ namespace cryptonote { CHECK_CORE_BUSY(); std::vector<crypto::key_image> key_images; - BOOST_FOREACH(const auto& ki_hex_str, req.key_images) + for(const auto& ki_hex_str: req.key_images) { blobdata b; if(!string_tools::parse_hexstr_to_binbuff(ki_hex_str, b)) @@ -616,6 +615,23 @@ namespace cryptonote return true; } + unsigned int concurrency_count = boost::thread::hardware_concurrency() * 4; + + // if we couldn't detect threads, set it to a ridiculously high number + if(concurrency_count == 0) + { + concurrency_count = 257; + } + + // if there are more threads requested than the hardware supports + // then we fail and log that. + if(req.threads_count > concurrency_count) + { + res.status = "Failed, too many threads relative to CPU cores."; + LOG_PRINT_L0(res.status); + return true; + } + boost::thread::attributes attrs; attrs.set_stack_size(THREAD_STACK_SIZE); @@ -908,7 +924,7 @@ namespace cryptonote uint64_t core_rpc_server::get_block_reward(const block& blk) { uint64_t reward = 0; - BOOST_FOREACH(const tx_out& out, blk.miner_tx.vout) + for(const tx_out& out: blk.miner_tx.vout) { reward += out.amount; } diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 50509040c..f5e20be48 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -362,6 +362,33 @@ bool simple_wallet::seed_set_language(const std::vector<std::string> &args/* = s return true; } +bool simple_wallet::change_password(const std::vector<std::string> &args) +{ + const auto orig_pwd_container = get_and_verify_password(); + + if(orig_pwd_container == boost::none) + { + fail_msg_writer() << tr("Your original password was incorrect."); + return false; + } + + // prompts for a new password, this is not a new wallet so pass in false. + const auto pwd_container = tools::wallet2::password_prompt(false); + + try + { + m_wallet->rewrite(m_wallet_file, pwd_container->password()); + m_wallet->store(); + } + catch (const wallet_logic_error& e) + { + fail_msg_writer() << tr("Error with wallet rewrite: ") << e.what(); + return false; + } + + return true; +} + bool simple_wallet::set_always_confirm_transfers(const std::vector<std::string> &args/* = std::vector<std::string>()*/) { const auto pwd_container = get_and_verify_password(); @@ -865,33 +892,6 @@ void simple_wallet::print_seed(std::string seed) //---------------------------------------------------------------------------------------------------- static bool is_local_daemon(const std::string &address) { - // extract host - epee::net_utils::http::url_content u_c; - if (!epee::net_utils::parse_url(address, u_c)) - { - LOG_PRINT_L1("Failed to determine whether daemon is local, assuming not"); - return false; - } - if (u_c.host.empty()) - { - LOG_PRINT_L1("Failed to determine whether daemon is local, assuming not"); - return false; - } - - // resolve to IP - boost::asio::io_service io_service; - boost::asio::ip::tcp::resolver resolver(io_service); - boost::asio::ip::tcp::resolver::query query(u_c.host, ""); - boost::asio::ip::tcp::resolver::iterator i = resolver.resolve(query); - while (i != boost::asio::ip::tcp::resolver::iterator()) - { - const boost::asio::ip::tcp::endpoint &ep = *i; - if (ep.address().is_loopback()) - return true; - ++i; - } - - return false; } //---------------------------------------------------------------------------------------------------- bool simple_wallet::init(const boost::program_options::variables_map& vm) @@ -1155,14 +1155,15 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) // set --trusted-daemon if local try { - if (is_local_daemon(m_wallet->get_daemon_address())) + if (tools::is_local_address(m_wallet->get_daemon_address())) { - LOG_PRINT_L1(tr("Daemon is local, assuming trusted")); + MINFO(tr("Daemon is local, assuming trusted")); m_trusted_daemon = true; } } catch (const std::exception &e) { } + m_http_client.set_server(m_wallet->get_daemon_address()); m_wallet->callback(this); return true; } @@ -1560,7 +1561,7 @@ bool simple_wallet::start_mining(const std::vector<std::string>& args) } COMMAND_RPC_START_MINING::response res; - bool r = net_utils::invoke_http_json_remote_command2(m_wallet->get_daemon_address() + "/start_mining", req, res, m_http_client); + bool r = net_utils::invoke_http_json("/start_mining", req, res, m_http_client); std::string err = interpret_rpc_response(r, res.status); if (err.empty()) success_msg_writer() << tr("Mining started in daemon"); @@ -1577,7 +1578,7 @@ bool simple_wallet::stop_mining(const std::vector<std::string>& args) assert(m_wallet); COMMAND_RPC_STOP_MINING::request req; COMMAND_RPC_STOP_MINING::response res; - bool r = net_utils::invoke_http_json_remote_command2(m_wallet->get_daemon_address() + "/stop_mining", req, res, m_http_client); + bool r = net_utils::invoke_http_json("/stop_mining", req, res, m_http_client); std::string err = interpret_rpc_response(r, res.status); if (err.empty()) success_msg_writer() << tr("Mining stopped in daemon"); @@ -1594,7 +1595,7 @@ bool simple_wallet::save_bc(const std::vector<std::string>& args) assert(m_wallet); COMMAND_RPC_SAVE_BC::request req; COMMAND_RPC_SAVE_BC::response res; - bool r = net_utils::invoke_http_json_remote_command2(m_wallet->get_daemon_address() + "/save_bc", req, res, m_http_client); + bool r = net_utils::invoke_http_json("/save_bc", req, res, m_http_client); std::string err = interpret_rpc_response(r, res.status); if (err.empty()) success_msg_writer() << tr("Blockchain saved"); @@ -1883,7 +1884,7 @@ uint64_t simple_wallet::get_daemon_blockchain_height(std::string& err) COMMAND_RPC_GET_HEIGHT::request req; COMMAND_RPC_GET_HEIGHT::response res = boost::value_initialized<COMMAND_RPC_GET_HEIGHT::response>(); - bool r = net_utils::invoke_http_json_remote_command2(m_wallet->get_daemon_address() + "/getheight", req, res, m_http_client); + bool r = net_utils::invoke_http_json("/getheight", req, res, m_http_client); err = interpret_rpc_response(r, res.status); return res.height; } @@ -1994,7 +1995,7 @@ bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending req.outputs[j].index = absolute_offsets[j]; } COMMAND_RPC_GET_OUTPUTS_BIN::response res = AUTO_VAL_INIT(res); - bool r = net_utils::invoke_http_bin_remote_command2(m_wallet->get_daemon_address() + "/get_outs.bin", req, res, m_http_client); + bool r = net_utils::invoke_http_bin("/get_outs.bin", req, res, m_http_client); err = interpret_rpc_response(r, res.status); if (!err.empty()) { @@ -2143,7 +2144,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri cryptonote::tx_destination_entry de; bool has_payment_id; crypto::hash8 new_payment_id; - if (!tools::dns_utils::get_account_address_from_str_or_url(de.addr, has_payment_id, new_payment_id, m_wallet->testnet(), local_args[i])) + if (!cryptonote::get_account_address_from_str_or_url(de.addr, has_payment_id, new_payment_id, m_wallet->testnet(), local_args[i])) return true; if (has_payment_id) @@ -2636,7 +2637,7 @@ bool simple_wallet::sweep_all(const std::vector<std::string> &args_) bool has_payment_id; crypto::hash8 new_payment_id; cryptonote::account_public_address address; - if (!tools::dns_utils::get_account_address_from_str_or_url(address, has_payment_id, new_payment_id, m_wallet->testnet(), local_args[0])) + if (!cryptonote::get_account_address_from_str_or_url(address, has_payment_id, new_payment_id, m_wallet->testnet(), local_args[0])) return true; if (has_payment_id) @@ -3187,7 +3188,7 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_) cryptonote::account_public_address address; bool has_payment_id; crypto::hash8 payment_id; - if(!tools::dns_utils::get_account_address_from_str_or_url(address, has_payment_id, payment_id, m_wallet->testnet(), local_args[2])) + if(!cryptonote::get_account_address_from_str_or_url(address, has_payment_id, payment_id, m_wallet->testnet(), local_args[2])) { fail_msg_writer() << tr("failed to parse address"); return true; @@ -3196,7 +3197,7 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_) COMMAND_RPC_GET_TRANSACTIONS::request req; COMMAND_RPC_GET_TRANSACTIONS::response res; req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid)); - if (!net_utils::invoke_http_json_remote_command2(m_wallet->get_daemon_address() + "/gettransactions", req, res, m_http_client) || + if (!net_utils::invoke_http_json("/gettransactions", req, res, m_http_client) || (res.txs.size() != 1 && res.txs_as_hex.size() != 1)) { fail_msg_writer() << tr("failed to get transaction from daemon"); @@ -3735,7 +3736,7 @@ bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::v cryptonote::account_public_address address; bool has_payment_id; crypto::hash8 payment_id8; - if(!tools::dns_utils::get_account_address_from_str_or_url(address, has_payment_id, payment_id8, m_wallet->testnet(), args[1])) + if(!cryptonote::get_account_address_from_str_or_url(address, has_payment_id, payment_id8, m_wallet->testnet(), args[1])) { fail_msg_writer() << tr("failed to parse address"); return true; @@ -3925,7 +3926,7 @@ bool simple_wallet::verify(const std::vector<std::string> &args) cryptonote::account_public_address address; bool has_payment_id; crypto::hash8 payment_id; - if(!tools::dns_utils::get_account_address_from_str_or_url(address, has_payment_id, payment_id, m_wallet->testnet(), address_string)) + if(!cryptonote::get_account_address_from_str_or_url(address, has_payment_id, payment_id, m_wallet->testnet(), address_string)) { fail_msg_writer() << tr("failed to parse address"); return true; diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 237c1e3e1..9918300df 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -162,6 +162,7 @@ namespace cryptonote bool export_outputs(const std::vector<std::string> &args); bool import_outputs(const std::vector<std::string> &args); bool show_transfer(const std::vector<std::string> &args); + bool change_password(const std::vector<std::string>& args); uint64_t get_daemon_blockchain_height(std::string& err); bool try_connect_to_daemon(bool silent = false, uint32_t* version = nullptr); diff --git a/src/wallet/api/utils.cpp b/src/wallet/api/utils.cpp index 0d30b61cd..788d98f25 100644 --- a/src/wallet/api/utils.cpp +++ b/src/wallet/api/utils.cpp @@ -31,50 +31,16 @@ #include "include_base_utils.h" // LOG_PRINT_x -#include "net/http_client.h" // epee::net_utils::... -#include <boost/asio.hpp> +#include "common/util.h" using namespace std; namespace Monero { namespace Utils { - -// copy-pasted from simplewallet. - bool isAddressLocal(const std::string &address) { - // extract host - epee::net_utils::http::url_content u_c; - if (!epee::net_utils::parse_url(address, u_c)) - { - LOG_PRINT_L1("Failed to determine whether daemon is local, assuming not"); - return false; - } - if (u_c.host.empty()) - { - LOG_PRINT_L1("Failed to determine whether daemon is local, assuming not"); - return false; - } - // resolver::resolve can throw an exception - try { - // resolve to IP - boost::asio::io_service io_service; - boost::asio::ip::tcp::resolver resolver(io_service); - boost::asio::ip::tcp::resolver::query query(u_c.host, "", boost::asio::ip::tcp::resolver::query::canonical_name); - boost::asio::ip::tcp::resolver::iterator i = resolver.resolve(query); - while (i != boost::asio::ip::tcp::resolver::iterator()) - { - const boost::asio::ip::tcp::endpoint &ep = *i; - if (ep.address().is_loopback()) - return true; - ++i; - } - } catch (const boost::system::system_error &e) { - LOG_ERROR("Failed to resolve " << address << ", :" << e.what()); - } - - return false; + return tools::is_local_address(address); } } diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 52ecc2e6a..9e40d2e02 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -197,6 +197,44 @@ bool Wallet::addressValid(const std::string &str, bool testnet) return get_account_integrated_address_from_str(address, has_payment_id, pid, testnet, str); } +bool Wallet::keyValid(const std::string &secret_key_string, const std::string &address_string, bool isViewKey, bool testnet, std::string &error) +{ + bool has_payment_id; + cryptonote::account_public_address address; + crypto::hash8 pid; + if(!get_account_integrated_address_from_str(address, has_payment_id, pid, testnet, address_string)) { + error = tr("Failed to parse address"); + return false; + } + + cryptonote::blobdata key_data; + if(!epee::string_tools::parse_hexstr_to_binbuff(secret_key_string, key_data) || key_data.size() != sizeof(crypto::secret_key)) + { + error = tr("Failed to parse key"); + return false; + } + crypto::secret_key key = *reinterpret_cast<const crypto::secret_key*>(key_data.data()); + + // check the key match the given address + crypto::public_key pkey; + if (!crypto::secret_key_to_public_key(key, pkey)) { + error = tr("failed to verify key"); + return false; + } + bool matchAddress = false; + if(isViewKey) + matchAddress = address.m_view_public_key == pkey; + else + matchAddress = address.m_spend_public_key == pkey; + + if(!matchAddress) { + error = tr("key does not match address"); + return false; + } + + return true; +} + std::string Wallet::paymentIdFromAddress(const std::string &str, bool testnet) { bool has_payment_id; @@ -337,6 +375,98 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas return true; } +bool WalletImpl::recoverFromKeys(const std::string &path, + const std::string &language, + const std::string &address_string, + const std::string &viewkey_string, + const std::string &spendkey_string) +{ + cryptonote::account_public_address address; + bool has_payment_id; + crypto::hash8 new_payment_id; + if(!get_account_integrated_address_from_str(address, has_payment_id, new_payment_id, m_wallet->testnet(), address_string)) + { + m_errorString = tr("failed to parse address"); + m_status = Status_Error; + return false; + } + + // parse optional spend key + crypto::secret_key spendkey; + bool has_spendkey = false; + if (!spendkey_string.empty()) { + cryptonote::blobdata spendkey_data; + if(!epee::string_tools::parse_hexstr_to_binbuff(spendkey_string, spendkey_data) || spendkey_data.size() != sizeof(crypto::secret_key)) + { + m_errorString = tr("failed to parse secret spend key"); + m_status = Status_Error; + return false; + } + has_spendkey = true; + spendkey = *reinterpret_cast<const crypto::secret_key*>(spendkey_data.data()); + } + + // parse view secret key + if (viewkey_string.empty()) { + m_errorString = tr("No view key supplied, cancelled"); + m_status = Status_Error; + return false; + } + cryptonote::blobdata viewkey_data; + if(!epee::string_tools::parse_hexstr_to_binbuff(viewkey_string, viewkey_data) || viewkey_data.size() != sizeof(crypto::secret_key)) + { + m_errorString = tr("failed to parse secret view key"); + m_status = Status_Error; + return false; + } + crypto::secret_key viewkey = *reinterpret_cast<const crypto::secret_key*>(viewkey_data.data()); + + // check the spend and view keys match the given address + crypto::public_key pkey; + if(has_spendkey) { + if (!crypto::secret_key_to_public_key(spendkey, pkey)) { + m_errorString = tr("failed to verify secret spend key"); + m_status = Status_Error; + return false; + } + if (address.m_spend_public_key != pkey) { + m_errorString = tr("spend key does not match address"); + m_status = Status_Error; + return false; + } + } + if (!crypto::secret_key_to_public_key(viewkey, pkey)) { + m_errorString = tr("failed to verify secret view key"); + m_status = Status_Error; + return false; + } + if (address.m_view_public_key != pkey) { + m_errorString = tr("view key does not match address"); + m_status = Status_Error; + return false; + } + + try + { + if (has_spendkey) { + m_wallet->generate(path, "", address, spendkey, viewkey); + LOG_PRINT_L1("Generated new wallet from keys"); + } + else { + m_wallet->generate(path, "", address, viewkey); + LOG_PRINT_L1("Generated new view only wallet from keys"); + } + + } + catch (const std::exception& e) { + m_errorString = string(tr("failed to generate new wallet: ")) + e.what(); + m_status = Status_Error; + return false; + } + return true; +} + + bool WalletImpl::open(const std::string &path, const std::string &password) { clearStatus(); @@ -516,12 +646,12 @@ string WalletImpl::keysFilename() const bool WalletImpl::init(const std::string &daemon_address, uint64_t upper_transaction_size_limit) { clearStatus(); - doInit(daemon_address, upper_transaction_size_limit); + if (!doInit(daemon_address, upper_transaction_size_limit)) + return false; bool result = this->refresh(); // enabling background refresh thread startRefresh(); return result; - } void WalletImpl::initAsync(const string &daemon_address, uint64_t upper_transaction_size_limit) @@ -1232,9 +1362,10 @@ bool WalletImpl::isNewWallet() const return !(blockChainHeight() > 1 || m_recoveringFromSeed || m_rebuildWalletCache) && !watchOnly(); } -void WalletImpl::doInit(const string &daemon_address, uint64_t upper_transaction_size_limit) +bool WalletImpl::doInit(const string &daemon_address, uint64_t upper_transaction_size_limit) { - m_wallet->init(daemon_address, upper_transaction_size_limit); + if (!m_wallet->init(daemon_address, upper_transaction_size_limit)) + return false; // in case new wallet, this will force fast-refresh (pulling hashes instead of blocks) // If daemon isn't synced a calculated block height will be used instead @@ -1253,8 +1384,7 @@ void WalletImpl::doInit(const string &daemon_address, uint64_t upper_transaction this->setTrustedDaemon(false); m_refreshIntervalMillis = DEFAULT_REMOTE_NODE_REFRESH_INTERVAL_MILLIS; } - - + return true; } bool WalletImpl::parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector<std::string> &unknown_parameters, std::string &error) diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index e3df7fd01..7daf63e43 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -58,6 +58,11 @@ public: const std::string &language) const; bool open(const std::string &path, const std::string &password); bool recover(const std::string &path, const std::string &seed); + bool recoverFromKeys(const std::string &path, + const std::string &language, + const std::string &address_string, + const std::string &viewkey_string, + const std::string &spendkey_string = ""); bool close(); std::string seed() const; std::string getSeedLanguage() const; @@ -94,6 +99,7 @@ public: void setRecoveringFromSeed(bool recoveringFromSeed); bool watchOnly() const; bool rescanSpent(); + bool testnet() const {return m_wallet->testnet();} PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id, @@ -127,7 +133,7 @@ private: bool daemonSynced() const; void stopRefresh(); bool isNewWallet() const; - void doInit(const std::string &daemon_address, uint64_t upper_transaction_size_limit); + bool doInit(const std::string &daemon_address, uint64_t upper_transaction_size_limit); private: diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp index 904338a72..c761cc6d2 100644 --- a/src/wallet/api/wallet_manager.cpp +++ b/src/wallet/api/wallet_manager.cpp @@ -43,6 +43,15 @@ namespace epee { unsigned int g_test_dbg_lock_sleep = 0; } +namespace { + template<typename Request, typename Response> + bool connect_and_invoke(const std::string& address, const std::string& path, const Request& request, Response& response) + { + epee::net_utils::http::http_simple_client client{}; + return client.set_server(address) && epee::net_utils::invoke_http_json(path, request, response, client); + } +} + namespace Monero { Wallet *WalletManagerImpl::createWallet(const std::string &path, const std::string &password, @@ -72,6 +81,22 @@ Wallet *WalletManagerImpl::recoveryWallet(const std::string &path, const std::st return wallet; } +Wallet *WalletManagerImpl::createWalletFromKeys(const std::string &path, + const std::string &language, + bool testnet, + uint64_t restoreHeight, + const std::string &addressString, + const std::string &viewKeyString, + const std::string &spendKeyString) +{ + WalletImpl * wallet = new WalletImpl(testnet); + if(restoreHeight > 0){ + wallet->setRefreshFromBlockHeight(restoreHeight); + } + wallet->recoverFromKeys(path, language, addressString, viewKeyString, spendKeyString); + return wallet; +} + bool WalletManagerImpl::closeWallet(Wallet *wallet) { WalletImpl * wallet_ = dynamic_cast<WalletImpl*>(wallet); @@ -145,9 +170,7 @@ bool WalletManagerImpl::connected(uint32_t *version) const req_t.jsonrpc = "2.0"; req_t.id = epee::serialization::storage_entry(0); req_t.method = "get_version"; - epee::net_utils::http::http_simple_client http_client; - bool r = epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/json_rpc", req_t, resp_t, http_client); - if (!r) + if (!connect_and_invoke(m_daemonAddress, "/json_rpc", req_t, resp_t)) return false; if (version) @@ -193,8 +216,7 @@ bool WalletManagerImpl::checkPayment(const std::string &address_text, const std: cryptonote::COMMAND_RPC_GET_TRANSACTIONS::request req; cryptonote::COMMAND_RPC_GET_TRANSACTIONS::response res; req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid)); - epee::net_utils::http::http_simple_client http_client; - if (!epee::net_utils::invoke_http_json_remote_command2(daemon_address + "/gettransactions", req, res, http_client) || + if (!connect_and_invoke(m_daemonAddress, "/gettransactions", req, res) || (res.txs.size() != 1 && res.txs_as_hex.size() != 1)) { error = tr("failed to get transaction from daemon"); @@ -312,8 +334,7 @@ uint64_t WalletManagerImpl::blockchainHeight() const cryptonote::COMMAND_RPC_GET_INFO::request ireq; cryptonote::COMMAND_RPC_GET_INFO::response ires; - epee::net_utils::http::http_simple_client http_client; - if (!epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/getinfo", ireq, ires, http_client)) + if (!connect_and_invoke(m_daemonAddress, "/getinfo", ireq, ires)) return 0; return ires.height; } @@ -323,8 +344,7 @@ uint64_t WalletManagerImpl::blockchainTargetHeight() const cryptonote::COMMAND_RPC_GET_INFO::request ireq; cryptonote::COMMAND_RPC_GET_INFO::response ires; - epee::net_utils::http::http_simple_client http_client; - if (!epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/getinfo", ireq, ires, http_client)) + if (!connect_and_invoke(m_daemonAddress, "/getinfo", ireq, ires)) return 0; return ires.target_height >= ires.height ? ires.target_height : ires.height; } @@ -334,8 +354,7 @@ uint64_t WalletManagerImpl::networkDifficulty() const cryptonote::COMMAND_RPC_GET_INFO::request ireq; cryptonote::COMMAND_RPC_GET_INFO::response ires; - epee::net_utils::http::http_simple_client http_client; - if (!epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/getinfo", ireq, ires, http_client)) + if (!connect_and_invoke(m_daemonAddress, "/getinfo", ireq, ires)) return 0; return ires.difficulty; } @@ -346,7 +365,7 @@ double WalletManagerImpl::miningHashRate() const cryptonote::COMMAND_RPC_MINING_STATUS::response mres; epee::net_utils::http::http_simple_client http_client; - if (!epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/mining_status", mreq, mres, http_client)) + if (!connect_and_invoke(m_daemonAddress, "/mining_status", mreq, mres)) return 0.0; if (!mres.active) return 0.0; @@ -366,7 +385,7 @@ void WalletManagerImpl::hardForkInfo(uint8_t &version, uint64_t &earliest_height req_t.id = epee::serialization::storage_entry(0); req_t.method = "hard_fork_info"; req_t.params.version = 0; - bool r = epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/json_rpc", req_t, resp_t, http_client); + bool r = connect_and_invoke(m_daemonAddress, "/json_rpc", req_t, resp_t); if (!r || resp_t.result.status != CORE_RPC_STATUS_OK) return; version = resp_t.result.version; @@ -378,8 +397,7 @@ uint64_t WalletManagerImpl::blockTarget() const cryptonote::COMMAND_RPC_GET_INFO::request ireq; cryptonote::COMMAND_RPC_GET_INFO::response ires; - epee::net_utils::http::http_simple_client http_client; - if (!epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/getinfo", ireq, ires, http_client)) + if (!connect_and_invoke(m_daemonAddress, "/getinfo", ireq, ires)) return 0; return ires.target; } @@ -389,8 +407,7 @@ bool WalletManagerImpl::isMining() const cryptonote::COMMAND_RPC_MINING_STATUS::request mreq; cryptonote::COMMAND_RPC_MINING_STATUS::response mres; - epee::net_utils::http::http_simple_client http_client; - if (!epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/mining_status", mreq, mres, http_client)) + if (!connect_and_invoke(m_daemonAddress, "/mining_status", mreq, mres)) return false; return mres.active; } @@ -403,8 +420,7 @@ bool WalletManagerImpl::startMining(const std::string &address, uint32_t threads mreq.miner_address = address; mreq.threads_count = threads; - epee::net_utils::http::http_simple_client http_client; - if (!epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/start_mining", mreq, mres, http_client)) + if (!connect_and_invoke(m_daemonAddress, "/start_mining", mreq, mres)) return false; return mres.status == CORE_RPC_STATUS_OK; } @@ -414,8 +430,7 @@ bool WalletManagerImpl::stopMining() cryptonote::COMMAND_RPC_STOP_MINING::request mreq; cryptonote::COMMAND_RPC_STOP_MINING::response mres; - epee::net_utils::http::http_simple_client http_client; - if (!epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/stop_mining", mreq, mres, http_client)) + if (!connect_and_invoke(m_daemonAddress, "/stop_mining", mreq, mres)) return false; return mres.status == CORE_RPC_STATUS_OK; } diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h index ca9570254..ce9b70e96 100644 --- a/src/wallet/api/wallet_manager.h +++ b/src/wallet/api/wallet_manager.h @@ -41,6 +41,13 @@ public: const std::string &language, bool testnet); Wallet * openWallet(const std::string &path, const std::string &password, bool testnet); virtual Wallet * recoveryWallet(const std::string &path, const std::string &memo, bool testnet, uint64_t restoreHeight); + virtual Wallet * createWalletFromKeys(const std::string &path, + const std::string &language, + bool testnet, + uint64_t restoreHeight, + const std::string &addressString, + const std::string &viewKeyString, + const std::string &spendKeyString = ""); virtual bool closeWallet(Wallet *wallet); bool walletExists(const std::string &path); std::vector<std::string> findWallets(const std::string &path); diff --git a/src/wallet/node_rpc_proxy.cpp b/src/wallet/node_rpc_proxy.cpp index d7f755e36..cc249b5cc 100644 --- a/src/wallet/node_rpc_proxy.cpp +++ b/src/wallet/node_rpc_proxy.cpp @@ -36,18 +36,16 @@ using namespace epee; namespace tools { -void NodeRPCProxy::init(const std::string &daemon_address) -{ - m_daemon_address = daemon_address; - - m_height = 0; - m_height_time = 0; - for (auto &slot: m_earliest_height) - slot = 0; - m_dynamic_per_kb_fee_estimate = 0; - m_dynamic_per_kb_fee_estimate_cached_height = 0; - m_dynamic_per_kb_fee_estimate_grace_blocks = 0; -} +NodeRPCProxy::NodeRPCProxy(epee::net_utils::http::http_simple_client &http_client, boost::mutex &mutex) + : m_http_client(http_client) + , m_daemon_rpc_mutex(mutex) + , m_height(0) + , m_height_time(0) + , m_earliest_height() + , m_dynamic_per_kb_fee_estimate(0) + , m_dynamic_per_kb_fee_estimate_cached_height(0) + , m_dynamic_per_kb_fee_estimate_grace_blocks(0) +{} boost::optional<std::string> NodeRPCProxy::get_height(uint64_t &height) { @@ -58,7 +56,7 @@ boost::optional<std::string> NodeRPCProxy::get_height(uint64_t &height) cryptonote::COMMAND_RPC_GET_HEIGHT::response res = AUTO_VAL_INIT(res); m_daemon_rpc_mutex.lock(); - bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/getheight", req, res, m_http_client); + bool r = net_utils::invoke_http_json("/getheight", req, res, m_http_client); m_daemon_rpc_mutex.unlock(); CHECK_AND_ASSERT_MES(r, std::string(), "Failed to connect to daemon"); CHECK_AND_ASSERT_MES(res.status != CORE_RPC_STATUS_BUSY, res.status, "Failed to connect to daemon"); @@ -87,7 +85,7 @@ boost::optional<std::string> NodeRPCProxy::get_earliest_height(uint8_t version, req_t.id = epee::serialization::storage_entry(0); req_t.method = "hard_fork_info"; req_t.params.version = version; - bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/json_rpc", req_t, resp_t, m_http_client); + bool r = net_utils::invoke_http_json("/json_rpc", req_t, resp_t, m_http_client); m_daemon_rpc_mutex.unlock(); CHECK_AND_ASSERT_MES(r, std::string(), "Failed to connect to daemon"); CHECK_AND_ASSERT_MES(resp_t.result.status != CORE_RPC_STATUS_BUSY, resp_t.result.status, "Failed to connect to daemon"); @@ -117,7 +115,7 @@ boost::optional<std::string> NodeRPCProxy::get_dynamic_per_kb_fee_estimate(uint6 req_t.id = epee::serialization::storage_entry(0); req_t.method = "get_fee_estimate"; req_t.params.grace_blocks = grace_blocks; - bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/json_rpc", req_t, resp_t, m_http_client); + bool r = net_utils::invoke_http_json("/json_rpc", req_t, resp_t, m_http_client); m_daemon_rpc_mutex.unlock(); CHECK_AND_ASSERT_MES(r, std::string(), "Failed to connect to daemon"); CHECK_AND_ASSERT_MES(resp_t.result.status != CORE_RPC_STATUS_BUSY, resp_t.result.status, "Failed to connect to daemon"); diff --git a/src/wallet/node_rpc_proxy.h b/src/wallet/node_rpc_proxy.h index 1ae716dab..e2f42d541 100644 --- a/src/wallet/node_rpc_proxy.h +++ b/src/wallet/node_rpc_proxy.h @@ -39,10 +39,7 @@ namespace tools class NodeRPCProxy { public: - NodeRPCProxy(epee::net_utils::http::http_simple_client &http_client, boost::mutex &mutex): - m_http_client(http_client), m_daemon_rpc_mutex(mutex) { init(""); } - - void init(const std::string &daemon_address); + NodeRPCProxy(epee::net_utils::http::http_simple_client &http_client, boost::mutex &mutex); boost::optional<std::string> get_height(uint64_t &height); void set_height(uint64_t h); @@ -50,7 +47,6 @@ public: boost::optional<std::string> get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks, uint64_t &fee); private: - std::string m_daemon_address; epee::net_utils::http::http_simple_client &m_http_client; boost::mutex &m_daemon_rpc_mutex; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 4348b8a62..148fb9d52 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -164,7 +164,7 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl daemon_address = std::string("http://") + daemon_host + ":" + std::to_string(daemon_port); std::unique_ptr<tools::wallet2> wallet(new tools::wallet2(testnet, restricted)); - wallet->init(daemon_address); + wallet->init(std::move(daemon_address)); return wallet; } @@ -418,6 +418,7 @@ namespace tools // for now, limit to 30 attempts. TODO: discuss a good number to limit to. const size_t MAX_SPLIT_ATTEMPTS = 30; +constexpr const std::chrono::seconds wallet2::rpc_timeout; const char* wallet2::tr(const char* str) { return i18n_translate(str, "tools::wallet2"); } bool wallet2::has_testnet_option(const boost::program_options::variables_map& vm) @@ -484,11 +485,11 @@ std::pair<std::unique_ptr<wallet2>, password_container> wallet2::make_new(const } //---------------------------------------------------------------------------------------------------- -void wallet2::init(const std::string& daemon_address, uint64_t upper_transaction_size_limit) +bool wallet2::init(std::string daemon_address, uint64_t upper_transaction_size_limit) { m_upper_transaction_size_limit = upper_transaction_size_limit; - m_daemon_address = daemon_address; - m_node_rpc_proxy.init(m_daemon_address); + m_daemon_address = std::move(daemon_address); + return m_http_client.set_server(get_daemon_address()); } //---------------------------------------------------------------------------------------------------- bool wallet2::is_deterministic() const @@ -841,7 +842,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s " not match with daemon response size=" + std::to_string(o_indices.size())); } - BOOST_FOREACH(size_t o, outs) + for(size_t o: outs) { THROW_WALLET_EXCEPTION_IF(tx.vout.size() <= o, error::wallet_internal_error, "wrong out in transaction: internal index=" + std::to_string(o) + ", total_outs=" + std::to_string(tx.vout.size())); @@ -945,7 +946,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s uint64_t tx_money_spent_in_ins = 0; // check all outputs for spending (compare key images) - BOOST_FOREACH(auto& in, tx.vin) + for(auto& in: tx.vin) { if(in.type() != typeid(cryptonote::txin_to_key)) continue; @@ -1106,7 +1107,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry TIME_MEASURE_FINISH(miner_tx_handle_time); TIME_MEASURE_START(txs_handle_time); - BOOST_FOREACH(auto& txblob, bche.txs) + for(auto& txblob: bche.txs) { cryptonote::transaction tx; bool r = parse_and_validate_tx_from_blob(txblob, tx); @@ -1169,7 +1170,7 @@ void wallet2::pull_blocks(uint64_t start_height, uint64_t &blocks_start_height, req.start_height = start_height; m_daemon_rpc_mutex.lock(); - bool r = net_utils::invoke_http_bin_remote_command2(m_daemon_address + "/getblocks.bin", req, res, m_http_client, WALLET_RCP_CONNECTION_TIMEOUT); + bool r = net_utils::invoke_http_bin("/getblocks.bin", req, res, m_http_client, rpc_timeout); m_daemon_rpc_mutex.unlock(); THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "getblocks.bin"); THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "getblocks.bin"); @@ -1191,7 +1192,7 @@ void wallet2::pull_hashes(uint64_t start_height, uint64_t &blocks_start_height, req.start_height = start_height; m_daemon_rpc_mutex.lock(); - bool r = net_utils::invoke_http_bin_remote_command2(m_daemon_address + "/gethashes.bin", req, res, m_http_client, WALLET_RCP_CONNECTION_TIMEOUT); + bool r = net_utils::invoke_http_bin("/gethashes.bin", req, res, m_http_client, rpc_timeout); m_daemon_rpc_mutex.unlock(); THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gethashes.bin"); THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gethashes.bin"); @@ -1275,7 +1276,7 @@ void wallet2::process_blocks(uint64_t start_height, const std::list<cryptonote:: } else { - BOOST_FOREACH(auto& bl_entry, blocks) + for(auto& bl_entry: blocks) { cryptonote::block bl; bool r = cryptonote::parse_and_validate_block_from_blob(bl_entry.block, bl); @@ -1353,7 +1354,7 @@ void wallet2::update_pool_state() cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL::request req; cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL::response res; m_daemon_rpc_mutex.lock(); - bool r = epee::net_utils::invoke_http_json_remote_command2(m_daemon_address + "/get_transaction_pool", req, res, m_http_client, 200000); + bool r = epee::net_utils::invoke_http_json("/get_transaction_pool", req, res, m_http_client, rpc_timeout); m_daemon_rpc_mutex.unlock(); THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_transaction_pool"); THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_transaction_pool"); @@ -1461,7 +1462,7 @@ void wallet2::update_pool_state() req.txs_hashes.push_back(it.id_hash); req.decode_as_json = false; m_daemon_rpc_mutex.lock(); - bool r = epee::net_utils::invoke_http_json_remote_command2(m_daemon_address + "/gettransactions", req, res, m_http_client, 200000); + bool r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout); m_daemon_rpc_mutex.unlock(); if (r && res.status == CORE_RPC_STATUS_OK) { @@ -1556,7 +1557,7 @@ void wallet2::fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, } } current_index = blocks_start_height; - BOOST_FOREACH(auto& bl_id, hashes) + for(auto& bl_id: hashes) { if(current_index >= m_blockchain.size()) { @@ -2262,15 +2263,7 @@ bool wallet2::check_connection(uint32_t *version, uint32_t timeout) if(!m_http_client.is_connected()) { - net_utils::http::url_content u; - net_utils::parse_url(m_daemon_address, u); - - if(!u.port) - { - u.port = m_testnet ? config::testnet::RPC_DEFAULT_PORT : config::RPC_DEFAULT_PORT; - } - - if (!m_http_client.connect(u.host, std::to_string(u.port), timeout)) + if (!m_http_client.connect(std::chrono::milliseconds(timeout))) return false; } @@ -2281,7 +2274,7 @@ bool wallet2::check_connection(uint32_t *version, uint32_t timeout) req_t.jsonrpc = "2.0"; req_t.id = epee::serialization::storage_entry(0); req_t.method = "get_version"; - bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/json_rpc", req_t, resp_t, m_http_client); + bool r = net_utils::invoke_http_json("/json_rpc", req_t, resp_t, m_http_client); if (!r || resp_t.result.status != CORE_RPC_STATUS_OK) *version = 0; else @@ -2514,7 +2507,7 @@ void wallet2::store_to(const std::string &path, const std::string &password) uint64_t wallet2::unlocked_balance() const { uint64_t amount = 0; - BOOST_FOREACH(const transfer_details& td, m_transfers) + for(const transfer_details& td: m_transfers) if(!td.m_spent && is_transfer_unlocked(td)) amount += td.amount(); @@ -2524,12 +2517,12 @@ uint64_t wallet2::unlocked_balance() const uint64_t wallet2::balance() const { uint64_t amount = 0; - BOOST_FOREACH(auto& td, m_transfers) + for(auto& td: m_transfers) if(!td.m_spent) amount += td.amount(); - BOOST_FOREACH(auto& utx, m_unconfirmed_txs) + for(auto& utx: m_unconfirmed_txs) if (utx.second.m_state != wallet2::unconfirmed_transfer_details::failed) amount+= utx.second.m_change; @@ -2602,7 +2595,7 @@ void wallet2::rescan_spent() COMMAND_RPC_IS_KEY_IMAGE_SPENT::response daemon_resp = AUTO_VAL_INIT(daemon_resp); req.key_images = key_images; m_daemon_rpc_mutex.lock(); - bool r = epee::net_utils::invoke_http_json_remote_command2(m_daemon_address + "/is_key_image_spent", req, daemon_resp, m_http_client, 200000); + bool r = epee::net_utils::invoke_http_json("/is_key_image_spent", req, daemon_resp, m_http_client, rpc_timeout); m_daemon_rpc_mutex.unlock(); THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "is_key_image_spent"); THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "is_key_image_spent"); @@ -2976,7 +2969,7 @@ void wallet2::commit_tx(pending_tx& ptx) req.do_not_relay = false; COMMAND_RPC_SEND_RAW_TX::response daemon_send_resp; m_daemon_rpc_mutex.lock(); - bool r = epee::net_utils::invoke_http_json_remote_command2(m_daemon_address + "/sendrawtransaction", req, daemon_send_resp, m_http_client, 200000); + bool r = epee::net_utils::invoke_http_json("/sendrawtransaction", req, daemon_send_resp, m_http_client, rpc_timeout); m_daemon_rpc_mutex.unlock(); THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "sendrawtransaction"); THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "sendrawtransaction"); @@ -2997,7 +2990,7 @@ void wallet2::commit_tx(pending_tx& ptx) { payment_id = get_payment_id(ptx); dests = ptx.dests; - BOOST_FOREACH(size_t idx, ptx.selected_transfers) + for(size_t idx: ptx.selected_transfers) amount_in += m_transfers[idx].amount(); } add_unconfirmed_tx(ptx.tx, amount_in, dests, payment_id, ptx.change_dts.amount); @@ -3008,13 +3001,13 @@ void wallet2::commit_tx(pending_tx& ptx) LOG_PRINT_L2("transaction " << txid << " generated ok and sent to daemon, key_images: [" << ptx.key_images << "]"); - BOOST_FOREACH(size_t idx, ptx.selected_transfers) + for(size_t idx: ptx.selected_transfers) { set_spent(idx, 0); } //fee includes dust if dust policy specified it. - LOG_PRINT_L0("Transaction successfully sent. <" << txid << ">" << ENDL + LOG_PRINT_L1("Transaction successfully sent. <" << txid << ">" << ENDL << "Commission: " << print_money(ptx.fee) << " (dust sent to dust addr: " << print_money((ptx.dust_added_to_fee ? 0 : ptx.dust)) << ")" << ENDL << "Balance: " << print_money(balance()) << ENDL << "Unlocked: " << print_money(unlocked_balance()) << ENDL @@ -3356,7 +3349,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<crypto ptx_vector.push_back(ptx); // mark transfers to be used as "spent" - BOOST_FOREACH(size_t idx, ptx.selected_transfers) + for(size_t idx: ptx.selected_transfers) { set_spent(idx, 0); } @@ -3368,7 +3361,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<crypto for (auto & ptx : ptx_vector) { // mark transfers to be used as not spent - BOOST_FOREACH(size_t idx2, ptx.selected_transfers) + for(size_t idx2: ptx.selected_transfers) { set_unspent(idx2); } @@ -3387,7 +3380,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<crypto for (auto & ptx : ptx_vector) { // mark transfers to be used as not spent - BOOST_FOREACH(size_t idx2, ptx.selected_transfers) + for(size_t idx2: ptx.selected_transfers) { set_unspent(idx2); } @@ -3406,7 +3399,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<crypto for (auto & ptx : ptx_vector) { // mark transfers to be used as not spent - BOOST_FOREACH(size_t idx2, ptx.selected_transfers) + for(size_t idx2: ptx.selected_transfers) { set_unspent(idx2); } @@ -3437,7 +3430,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> req_t.params.amounts.resize(std::distance(req_t.params.amounts.begin(), end)); req_t.params.unlocked = true; req_t.params.recent_cutoff = time(NULL) - RECENT_OUTPUT_ZONE; - bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/json_rpc", req_t, resp_t, m_http_client); + bool r = net_utils::invoke_http_json("/json_rpc", req_t, resp_t, m_http_client); m_daemon_rpc_mutex.unlock(); THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "transfer_selected"); THROW_WALLET_EXCEPTION_IF(resp_t.result.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_histogram"); @@ -3564,7 +3557,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> // get the keys for those m_daemon_rpc_mutex.lock(); - r = epee::net_utils::invoke_http_bin_remote_command2(m_daemon_address + "/get_outs.bin", req, daemon_resp, m_http_client, 200000); + r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, daemon_resp, m_http_client, rpc_timeout); m_daemon_rpc_mutex.unlock(); THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_outs.bin"); THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_outs.bin"); @@ -3667,7 +3660,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent // calculate total amount being sent to all destinations // throw if total amount overflows uint64_t - BOOST_FOREACH(auto& dt, dsts) + for(auto& dt: dsts) { THROW_WALLET_EXCEPTION_IF(0 == dt.amount, error::zero_destination); needed_money += dt.amount; @@ -3676,7 +3669,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent } uint64_t found_money = 0; - BOOST_FOREACH(size_t idx, selected_transfers) + for(size_t idx: selected_transfers) { found_money += m_transfers[idx].amount(); } @@ -3692,7 +3685,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent typedef cryptonote::tx_source_entry::output_entry tx_output_entry; size_t i = 0, out_index = 0; std::vector<cryptonote::tx_source_entry> sources; - BOOST_FOREACH(size_t idx, selected_transfers) + for(size_t idx: selected_transfers) { sources.resize(sources.size()+1); cryptonote::tx_source_entry& src = sources.back(); @@ -3743,11 +3736,11 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent std::vector<cryptonote::tx_destination_entry> splitted_dsts, dust_dsts; uint64_t dust = 0; destination_split_strategy(dsts, change_dts, dust_policy.dust_threshold, splitted_dsts, dust_dsts); - BOOST_FOREACH(auto& d, dust_dsts) { + for(auto& d: dust_dsts) { THROW_WALLET_EXCEPTION_IF(dust_policy.dust_threshold < d.amount, error::wallet_internal_error, "invalid dust value: dust = " + std::to_string(d.amount) + ", dust_threshold = " + std::to_string(dust_policy.dust_threshold)); } - BOOST_FOREACH(auto& d, dust_dsts) { + for(auto& d: dust_dsts) { if (!dust_policy.add_to_fee) splitted_dsts.push_back(cryptonote::tx_destination_entry(d.amount, dust_policy.addr_for_dust)); dust += d.amount; @@ -3812,7 +3805,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry // calculate total amount being sent to all destinations // throw if total amount overflows uint64_t - BOOST_FOREACH(auto& dt, dsts) + for(auto& dt: dsts) { THROW_WALLET_EXCEPTION_IF(0 == dt.amount, error::zero_destination); needed_money += dt.amount; @@ -3821,7 +3814,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry } uint64_t found_money = 0; - BOOST_FOREACH(size_t idx, selected_transfers) + for(size_t idx: selected_transfers) { found_money += m_transfers[idx].amount(); } @@ -3836,7 +3829,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry LOG_PRINT_L2("preparing outputs"); size_t i = 0, out_index = 0; std::vector<cryptonote::tx_source_entry> sources; - BOOST_FOREACH(size_t idx, selected_transfers) + for(size_t idx: selected_transfers) { sources.resize(sources.size()+1); cryptonote::tx_source_entry& src = sources.back(); @@ -4107,7 +4100,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp // calculate total amount being sent to all destinations // throw if total amount overflows uint64_t needed_money = 0; - BOOST_FOREACH(auto& dt, dsts) + for(auto& dt: dsts) { THROW_WALLET_EXCEPTION_IF(0 == dt.amount, error::zero_destination); needed_money += dt.amount; @@ -4119,7 +4112,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp THROW_WALLET_EXCEPTION_IF(needed_money == 0, error::zero_destination); // gather all our dust and non dust outputs - for (size_t i = 0; i < m_transfers.size(); ++i) + const std::vector<size_t> unused_indices = select_available_outputs_from_histogram(fake_outs_count + 1, true, true, trusted_daemon); + for (size_t i: unused_indices) { const transfer_details& td = m_transfers[i]; if (!td.m_spent && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td)) @@ -4636,7 +4630,7 @@ std::vector<size_t> wallet2::select_available_outputs_from_histogram(uint64_t co req_t.params.min_count = count; req_t.params.max_count = 0; req_t.params.unlocked = unlocked; - bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/json_rpc", req_t, resp_t, m_http_client); + bool r = net_utils::invoke_http_json("/json_rpc", req_t, resp_t, m_http_client); m_daemon_rpc_mutex.unlock(); THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "select_available_unmixable_outputs"); THROW_WALLET_EXCEPTION_IF(resp_t.result.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_histogram"); @@ -4675,7 +4669,7 @@ uint64_t wallet2::get_num_rct_outputs() req_t.params.amounts.push_back(0); req_t.params.min_count = 0; req_t.params.max_count = 0; - bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/json_rpc", req_t, resp_t, m_http_client); + bool r = net_utils::invoke_http_json("/json_rpc", req_t, resp_t, m_http_client); m_daemon_rpc_mutex.unlock(); THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_num_rct_outputs"); THROW_WALLET_EXCEPTION_IF(resp_t.result.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_histogram"); @@ -4784,7 +4778,7 @@ uint64_t wallet2::get_daemon_blockchain_target_height(string &err) req_t.jsonrpc = "2.0"; req_t.id = epee::serialization::storage_entry(0); req_t.method = "get_info"; - bool ok = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/json_rpc", req_t, resp_t, m_http_client); + bool ok = net_utils::invoke_http_json("/json_rpc", req_t, resp_t, m_http_client); m_daemon_rpc_mutex.unlock(); if (ok) { @@ -5097,7 +5091,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag } m_daemon_rpc_mutex.lock(); - bool r = epee::net_utils::invoke_http_json_remote_command2(m_daemon_address + "/is_key_image_spent", req, daemon_resp, m_http_client, 200000); + bool r = epee::net_utils::invoke_http_json("/is_key_image_spent", req, daemon_resp, m_http_client, rpc_timeout); m_daemon_rpc_mutex.unlock(); THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "is_key_image_spent"); THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "is_key_image_spent"); @@ -5407,7 +5401,7 @@ uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, ui height_mid, height_max }; - bool r = net_utils::invoke_http_bin_remote_command2(get_daemon_address() + "/getblocks_by_height.bin", req, res, m_http_client); + bool r = net_utils::invoke_http_bin("/getblocks_by_height.bin", req, res, m_http_client); if (!r || res.status != CORE_RPC_STATUS_OK) { std::ostringstream oss; @@ -5424,9 +5418,9 @@ uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, ui throw std::runtime_error(oss.str()); } cryptonote::block blk_min, blk_mid, blk_max; - if (!parse_and_validate_block_from_blob(res.blocks[0].block, blk_min)) throw std::runtime_error("failed to parse blob at height " + height_min); - if (!parse_and_validate_block_from_blob(res.blocks[1].block, blk_mid)) throw std::runtime_error("failed to parse blob at height " + height_mid); - if (!parse_and_validate_block_from_blob(res.blocks[2].block, blk_max)) throw std::runtime_error("failed to parse blob at height " + height_max); + if (!parse_and_validate_block_from_blob(res.blocks[0].block, blk_min)) throw std::runtime_error("failed to parse blob at height " + std::to_string(height_min)); + if (!parse_and_validate_block_from_blob(res.blocks[1].block, blk_mid)) throw std::runtime_error("failed to parse blob at height " + std::to_string(height_mid)); + if (!parse_and_validate_block_from_blob(res.blocks[2].block, blk_max)) throw std::runtime_error("failed to parse blob at height " + std::to_string(height_max)); uint64_t timestamp_min = blk_min.timestamp; uint64_t timestamp_mid = blk_mid.timestamp; uint64_t timestamp_max = blk_max.timestamp; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 629011800..91d4db47e 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -61,8 +61,6 @@ #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "wallet.wallet2" -#define WALLET_RCP_CONNECTION_TIMEOUT 200000 - class Serialization_portability_wallet_Test; namespace tools @@ -96,6 +94,8 @@ namespace tools { friend class ::Serialization_portability_wallet_Test; public: + static constexpr const std::chrono::seconds rpc_timeout = std::chrono::minutes(3) + std::chrono::seconds(30); + enum RefreshType { RefreshFull, RefreshOptimizeCoinbase, @@ -107,7 +107,7 @@ namespace tools wallet2(const wallet2&) : m_run(true), m_callback(0), m_testnet(false), m_always_confirm_transfers(true), m_print_ring_members(false), m_store_tx_info(true), m_default_mixin(0), m_default_priority(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0), m_confirm_missing_payment_id(true), m_node_rpc_proxy(m_http_client, m_daemon_rpc_mutex) {} public: - static const char* tr(const char* str);// { return i18n_translate(str, "cryptonote::simple_wallet"); } + static const char* tr(const char* str); static bool has_testnet_option(const boost::program_options::variables_map& vm); static void init_options(boost::program_options::options_description& desc_params); @@ -342,8 +342,8 @@ namespace tools // free block size. TODO: fix this so that it actually takes // into account the current median block size rather than // the minimum block size. - void init(const std::string& daemon_address = "http://localhost:8080", uint64_t upper_transaction_size_limit = 0); bool deinit(); + bool init(std::string daemon_address = "http://localhost:8080", uint64_t upper_transaction_size_limit = 0); void stop() { m_run.store(false, std::memory_order_relaxed); } @@ -924,7 +924,7 @@ namespace tools splitted_dsts.clear(); dust_dsts.clear(); - BOOST_FOREACH(auto& de, dsts) + for(auto& de: dsts) { cryptonote::decompose_amount_into_digits(de.amount, 0, [&](uint64_t chunk) { splitted_dsts.push_back(cryptonote::tx_destination_entry(chunk, de.addr)); }, @@ -987,7 +987,7 @@ namespace tools // calculate total amount being sent to all destinations // throw if total amount overflows uint64_t - BOOST_FOREACH(auto& dt, dsts) + for(auto& dt: dsts) { THROW_WALLET_EXCEPTION_IF(0 == dt.amount, error::zero_destination); needed_money += dt.amount; @@ -1008,7 +1008,7 @@ namespace tools { COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request req = AUTO_VAL_INIT(req); req.outs_count = fake_outputs_count + 1;// add one to make possible (if need) to skip real output key - BOOST_FOREACH(size_t idx, selected_transfers) + for(size_t idx: selected_transfers) { const transfer_container::const_iterator it = m_transfers.begin() + idx; THROW_WALLET_EXCEPTION_IF(it->m_tx.vout.size() <= it->m_internal_output_index, error::wallet_internal_error, @@ -1018,7 +1018,7 @@ namespace tools } m_daemon_rpc_mutex.lock(); - bool r = epee::net_utils::invoke_http_bin_remote_command2(m_daemon_address + "/getrandom_outs.bin", req, daemon_resp, m_http_client, 200000); + bool r = epee::net_utils::invoke_http_bin("/getrandom_outs.bin", req, daemon_resp, m_http_client, rpc_timeout); m_daemon_rpc_mutex.unlock(); THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "getrandom_outs.bin"); THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "getrandom_outs.bin"); @@ -1028,7 +1028,7 @@ namespace tools std::to_string(daemon_resp.outs.size()) + ", expected " + std::to_string(selected_transfers.size())); std::unordered_map<uint64_t, uint64_t> scanty_outs; - BOOST_FOREACH(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& amount_outs, daemon_resp.outs) + for(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& amount_outs: daemon_resp.outs) { if (amount_outs.outs.size() < fake_outputs_count) { @@ -1041,7 +1041,7 @@ namespace tools //prepare inputs size_t i = 0; std::vector<cryptonote::tx_source_entry> sources; - BOOST_FOREACH(size_t idx, selected_transfers) + for(size_t idx: selected_transfers) { sources.resize(sources.size()+1); cryptonote::tx_source_entry& src = sources.back(); @@ -1052,7 +1052,7 @@ namespace tools if(daemon_resp.outs.size()) { daemon_resp.outs[i].outs.sort([](const out_entry& a, const out_entry& b){return a.global_amount_index < b.global_amount_index;}); - BOOST_FOREACH(out_entry& daemon_oe, daemon_resp.outs[i].outs) + for(out_entry& daemon_oe: daemon_resp.outs[i].outs) { if(td.m_global_output_index == daemon_oe.global_amount_index) continue; @@ -1094,11 +1094,11 @@ namespace tools std::vector<cryptonote::tx_destination_entry> splitted_dsts, dust_dsts; uint64_t dust = 0; destination_split_strategy(dsts, change_dts, dust_policy.dust_threshold, splitted_dsts, dust_dsts); - BOOST_FOREACH(auto& d, dust_dsts) { + for(auto& d: dust_dsts) { THROW_WALLET_EXCEPTION_IF(dust_policy.dust_threshold < d.amount, error::wallet_internal_error, "invalid dust value: dust = " + std::to_string(d.amount) + ", dust_threshold = " + std::to_string(dust_policy.dust_threshold)); } - BOOST_FOREACH(auto& d, dust_dsts) { + for(auto& d: dust_dsts) { if (!dust_policy.add_to_fee) splitted_dsts.push_back(cryptonote::tx_destination_entry(d.amount, dust_policy.addr_for_dust)); dust += d.amount; diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index 78caddc0b..563f16eaa 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -295,6 +295,7 @@ struct Wallet virtual bool setPassword(const std::string &password) = 0; virtual std::string address() const = 0; virtual std::string path() const = 0; + virtual bool testnet() const = 0; /*! * \brief integratedAddress - returns integrated address for current wallet address and given payment_id. @@ -434,6 +435,7 @@ struct Wallet static std::string genPaymentId(); static bool paymentIdValid(const std::string &paiment_id); static bool addressValid(const std::string &str, bool testnet); + static bool keyValid(const std::string &secret_key_string, const std::string &address_string, bool isViewKey, bool testnet, std::string &error); static std::string paymentIdFromAddress(const std::string &str, bool testnet); static uint64_t maximumAllowedAmount(); @@ -613,6 +615,25 @@ struct WalletManager */ virtual Wallet * recoveryWallet(const std::string &path, const std::string &memo, bool testnet = false, uint64_t restoreHeight = 0) = 0; + /*! + * \brief recovers existing wallet using keys. Creates a view only wallet if spend key is omitted + * \param path Name of wallet file to be created + * \param language language + * \param testnet testnet + * \param restoreHeight restore from start height + * \param addressString public address + * \param viewKeyString view key + * \param spendKeyString spend key (optional) + * \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully) + */ + virtual Wallet * createWalletFromKeys(const std::string &path, + const std::string &language, + bool testnet, + uint64_t restoreHeight, + const std::string &addressString, + const std::string &viewKeyString, + const std::string &spendKeyString = "") = 0; + /*! * \brief Closes wallet. In case operation succeded, wallet object deleted. in case operation failed, wallet object not deleted * \param wallet previously opened / created wallet instance diff --git a/src/wallet/wallet_args.cpp b/src/wallet/wallet_args.cpp index b7a4532fd..12799f613 100644 --- a/src/wallet/wallet_args.cpp +++ b/src/wallet/wallet_args.cpp @@ -72,7 +72,8 @@ namespace wallet_args int argc, char** argv, const char* const usage, boost::program_options::options_description desc_params, - const boost::program_options::positional_options_description& positional_options) + const boost::program_options::positional_options_description& positional_options, + bool log_to_console) { namespace bf = boost::filesystem; @@ -138,7 +139,7 @@ namespace wallet_args log_path = command_line::get_arg(vm, arg_log_file); else log_path = mlog_get_default_log_path("monero-wallet-cli.log"); - mlog_configure(log_path, false); + mlog_configure(log_path, log_to_console); if (!vm["log-level"].defaulted()) { mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str()); diff --git a/src/wallet/wallet_args.h b/src/wallet/wallet_args.h index 17446abf3..e0719d203 100644 --- a/src/wallet/wallet_args.h +++ b/src/wallet/wallet_args.h @@ -49,5 +49,6 @@ namespace wallet_args int argc, char** argv, const char* const usage, boost::program_options::options_description desc_params, - const boost::program_options::positional_options_description& positional_options); + const boost::program_options::positional_options_description& positional_options, + bool log_to_console = false); } diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 33e099ceb..dcf8f8e6d 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -369,7 +369,7 @@ namespace tools cryptonote::set_payment_id_to_tx_extra_nonce(extra_nonce, long_payment_id); } /* or short payment ID */ - else if (!wallet2::parse_short_payment_id(payment_id_str, short_payment_id)) { + else if (wallet2::parse_short_payment_id(payment_id_str, short_payment_id)) { cryptonote::set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, short_payment_id); } else { @@ -1324,16 +1324,14 @@ int main(int argc, char** argv) { argc, argv, "monero-wallet-rpc [--wallet-file=<file>|--generate-from-json=<file>] [--rpc-bind-port=<port>]", desc_params, - po::positional_options_description() + po::positional_options_description(), + true ); if (!vm) { return 1; } - mlog_configure("monero-wallet-rpc.log", true); - mlog_set_log_level(2); - std::unique_ptr<tools::wallet2> wal; try { diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 557e3f07c..5851d9c6a 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -51,7 +51,7 @@ int main(int argc, char* argv[]) //set up logging options mlog_configure(mlog_get_default_log_path("core_tests.log"), true); - mlog_set_log_level(3); + mlog_set_log_level(2); po::options_description desc_options("Allowed options"); command_line::add_arg(desc_options, command_line::arg_help); diff --git a/tests/functional_tests/transactions_flow_test.cpp b/tests/functional_tests/transactions_flow_test.cpp index 73c79c237..5666f49bf 100644 --- a/tests/functional_tests/transactions_flow_test.cpp +++ b/tests/functional_tests/transactions_flow_test.cpp @@ -159,14 +159,14 @@ bool transactions_flow_test(std::string& working_folder, epee::net_utils::http::http_simple_client http_client; COMMAND_RPC_STOP_MINING::request daemon1_req = AUTO_VAL_INIT(daemon1_req); COMMAND_RPC_STOP_MINING::response daemon1_rsp = AUTO_VAL_INIT(daemon1_rsp); - bool r = net_utils::invoke_http_json_remote_command2(daemon_addr_a + "/stop_mine", daemon1_req, daemon1_rsp, http_client, 10000); + bool r = http_client.set_server(daemon_addr_a) && net_utils::invoke_http_json("/stop_mine", daemon1_req, daemon1_rsp, http_client, std::chrono::seconds(10)); CHECK_AND_ASSERT_MES(r, false, "failed to stop mining"); COMMAND_RPC_START_MINING::request daemon_req = AUTO_VAL_INIT(daemon_req); COMMAND_RPC_START_MINING::response daemon_rsp = AUTO_VAL_INIT(daemon_rsp); daemon_req.miner_address = w1.get_account().get_public_address_str(false); daemon_req.threads_count = 9; - r = net_utils::invoke_http_json_remote_command2(daemon_addr_a + "/start_mining", daemon_req, daemon_rsp, http_client, 10000); + r = net_utils::invoke_http_json("/start_mining", daemon_req, daemon_rsp, http_client, std::chrono::seconds(10)); CHECK_AND_ASSERT_MES(r, false, "failed to get getrandom_outs"); CHECK_AND_ASSERT_MES(daemon_rsp.status == CORE_RPC_STATUS_OK, false, "failed to getrandom_outs.bin"); |