From fff238ec94ac6d45fc18c315d7bc590ddfaad63d Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 19 Mar 2016 21:48:36 +0000 Subject: Print stack trace upon exceptions Useful for debugging users' logs --- src/wallet/wallet2.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/wallet/wallet2.cpp') diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 2afe08cb1..ef17a770b 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -32,6 +32,7 @@ #include #include +#include "common/exception.h" #include "include_base_utils.h" using namespace epee; @@ -803,7 +804,7 @@ void wallet2::refresh(uint64_t start_height, uint64_t & blocks_fetched, bool& re // handle error from async fetching thread if (error) { - throw std::runtime_error("proxy exception in refresh thread"); + throw tools::runtime_error("proxy exception in refresh thread"); } } catch (const std::exception&) @@ -2012,7 +2013,7 @@ std::vector wallet2::create_transactions(std::vector ptx_vector; -- cgit v1.2.3 From f7301c3563e7ae19b8d7c65d8bc88f3c42eefc09 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Mon, 21 Mar 2016 10:12:12 +0000 Subject: Revert "Print stack trace upon exceptions" Ain't nobody got time for link/cmake skullduggery. This reverts commit fff238ec94ac6d45fc18c315d7bc590ddfaad63d. --- CMakeLists.txt | 12 ---- cmake/FindLibunwind.cmake | 25 ------- contrib/epee/include/misc_log_ex.h | 2 +- contrib/epee/include/net/abstract_tcp_server2.inl | 2 +- .../include/storages/portable_storage_from_bin.h | 4 +- src/blockchain_db/blockchain_db.h | 3 +- src/blockchain_utilities/blockchain_export.cpp | 2 +- src/blockchain_utilities/blockchain_import.cpp | 6 +- src/blockchain_utilities/bootstrap_file.cpp | 44 ++++++------ src/blockchain_utilities/fake_core.h | 4 +- src/common/CMakeLists.txt | 3 - src/common/exception.cpp | 84 ---------------------- src/common/exception.h | 53 -------------- src/cryptonote_core/blockchain_storage.h | 3 +- src/cryptonote_core/checkpoints_create.cpp | 1 - src/cryptonote_core/cryptonote_core.cpp | 2 +- src/cryptonote_core/cryptonote_core.h | 1 - src/cryptonote_core/miner.cpp | 1 - .../cryptonote_protocol_handler.h | 1 - src/daemon/command_parser_executor.cpp | 1 - src/daemon/command_server.cpp | 1 - src/daemon/daemon.cpp | 6 +- src/daemon/p2p.h | 2 +- src/daemon/protocol.h | 2 +- src/daemon/rpc.h | 4 +- src/daemon/rpc_command_executor.cpp | 3 +- src/daemonizer/posix_fork.cpp | 3 +- src/miner/simpleminer.cpp | 1 - src/p2p/data_logger.cpp | 7 +- src/simplewallet/simplewallet.cpp | 2 +- src/wallet/wallet2.cpp | 5 +- src/wallet/wallet2.h | 1 - src/wallet/wallet2_api.cpp | 1 - tests/core_proxy/core_proxy.h | 2 +- tests/core_tests/chaingen.cpp | 12 ++-- tests/core_tests/chaingen.h | 6 +- tests/core_tests/tx_validation.cpp | 2 +- tests/net_load_tests/clt.cpp | 1 - tests/net_load_tests/srv.cpp | 1 - tests/unit_tests/ban.cpp | 2 +- tests/unit_tests/epee_boosted_tcp_server.cpp | 2 +- tests/unit_tests/mnemonics.cpp | 1 - tests/unit_tests/test_protocol_pack.cpp | 1 - 43 files changed, 63 insertions(+), 259 deletions(-) delete mode 100644 cmake/FindLibunwind.cmake delete mode 100644 src/common/exception.cpp delete mode 100644 src/common/exception.h (limited to 'src/wallet/wallet2.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index ea1d5d7e5..9674404bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -243,14 +243,6 @@ endif() add_definitions("-DBLOCKCHAIN_DB=${BLOCKCHAIN_DB}") -find_package(Libunwind) -if(LIBUNWIND_FOUND) - message(STATUS "Using libunwind to provide stack traces") - add_definitions("-DHAVE_LIBUNWIND") -else() - message(STATUS "Stack traces disabled") -endif() - if (UNIX AND NOT APPLE) # Note that at the time of this writing the -Wstrict-prototypes flag added below will make this fail set(THREADS_PREFER_PTHREAD_FLAG ON) @@ -282,10 +274,6 @@ if (BERKELEY_DB) include_directories(${BDB_INCLUDE}) endif() -# Final setup for libunwind -include_directories(${LIBUNWIND_INCLUDE}) -link_directories(${LIBUNWIND_LIBRARY_DIRS}) - if(MSVC) add_definitions("/bigobj /MP /W3 /GS- /D_CRT_SECURE_NO_WARNINGS /wd4996 /wd4345 /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0 /FIinline_c.h /D__SSE4_1__") # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Dinline=__inline") diff --git a/cmake/FindLibunwind.cmake b/cmake/FindLibunwind.cmake deleted file mode 100644 index 9946e7cdd..000000000 --- a/cmake/FindLibunwind.cmake +++ /dev/null @@ -1,25 +0,0 @@ -# - Try to find libunwind -# Once done this will define -# -# LIBUNWIND_FOUND - system has libunwind -# LIBUNWIND_INCLUDE_DIR - the libunwind include directory -# LIBUNWIND_LIBRARIES - Link these to use libunwind -# LIBUNWIND_DEFINITIONS - Compiler switches required for using libunwind - -# Copyright (c) 2006, Alexander Dymo, -# -# Redistribution and use is allowed according to the terms of the BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. - -find_path(LIBUNWIND_INCLUDE_DIR libunwind.h - /usr/include - /usr/local/include -) - -find_library(LIBUNWIND_LIBRARIES NAMES unwind ) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Libunwind "Could not find libunwind" LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARIES) -# show the LIBUNWIND_INCLUDE_DIR and LIBUNWIND_LIBRARIES variables only in the advanced view -mark_as_advanced(LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARIES ) - diff --git a/contrib/epee/include/misc_log_ex.h b/contrib/epee/include/misc_log_ex.h index 58d47c472..d1451ff12 100644 --- a/contrib/epee/include/misc_log_ex.h +++ b/contrib/epee/include/misc_log_ex.h @@ -1426,7 +1426,7 @@ POP_WARNINGS #define CATCH_ENTRY_L4(lacation, return_val) CATCH_ENTRY(lacation, return_val) -#define ASSERT_MES_AND_THROW(message) {LOG_ERROR(message); std::stringstream ss; ss << message; throw tools::runtime_error(ss.str());} +#define ASSERT_MES_AND_THROW(message) {LOG_ERROR(message); std::stringstream ss; ss << message; throw std::runtime_error(ss.str());} #define CHECK_AND_ASSERT_THROW_MES(expr, message) {if(!(expr)) ASSERT_MES_AND_THROW(message);} diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl index 2f6e52a5b..1c854dfb7 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -777,7 +777,7 @@ POP_WARNINGS { m_thread_name_prefix = prefix_name; auto it = server_type_map.find(m_thread_name_prefix); - if (it==server_type_map.end()) throw tools::runtime_error("Unknown prefix/server type:" + std::string(prefix_name)); + if (it==server_type_map.end()) throw std::runtime_error("Unknown prefix/server type:" + std::string(prefix_name)); auto connection_type = it->second; // the value of type _info_c("net/RPClog", "Set server type to: " << connection_type << " from name: " << m_thread_name_prefix); _info_c("net/RPClog", "prefix_name = " << prefix_name); diff --git a/contrib/epee/include/storages/portable_storage_from_bin.h b/contrib/epee/include/storages/portable_storage_from_bin.h index 4cb2003e0..bc2fb1463 100644 --- a/contrib/epee/include/storages/portable_storage_from_bin.h +++ b/contrib/epee/include/storages/portable_storage_from_bin.h @@ -84,9 +84,9 @@ namespace epee inline throwable_buffer_reader::throwable_buffer_reader(const void* ptr, size_t sz) { if(!ptr) - throw tools::runtime_error("throwable_buffer_reader: ptr==nullptr"); + throw std::runtime_error("throwable_buffer_reader: ptr==nullptr"); if(!sz) - throw tools::runtime_error("throwable_buffer_reader: sz==0"); + throw std::runtime_error("throwable_buffer_reader: sz==0"); m_ptr = (uint8_t*)ptr; m_count = sz; m_recursion_count = 0; diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index b9db6d196..3396b8c20 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -33,7 +33,6 @@ #include #include #include -#include "common/exception.h" #include "crypto/hash.h" #include "cryptonote_core/cryptonote_basic.h" #include "cryptonote_core/difficulty.h" @@ -152,7 +151,7 @@ struct output_data_t /*********************************** * Exception Definitions ***********************************/ -class DB_EXCEPTION : public tools::exception +class DB_EXCEPTION : public std::exception { private: std::string m; diff --git a/src/blockchain_utilities/blockchain_export.cpp b/src/blockchain_utilities/blockchain_export.cpp index 4c5e5fd02..964c610cd 100644 --- a/src/blockchain_utilities/blockchain_export.cpp +++ b/src/blockchain_utilities/blockchain_export.cpp @@ -198,7 +198,7 @@ int main(int argc, char* argv[]) else { LOG_ERROR("Attempted to use non-existent database type: " << db_type); - throw tools::runtime_error("Attempting to use non-existent database type"); + throw std::runtime_error("Attempting to use non-existent database type"); } LOG_PRINT_L0("database: " << db_type); diff --git a/src/blockchain_utilities/blockchain_import.cpp b/src/blockchain_utilities/blockchain_import.cpp index 43f6af6d5..1aaf2bddc 100644 --- a/src/blockchain_utilities/blockchain_import.cpp +++ b/src/blockchain_utilities/blockchain_import.cpp @@ -359,14 +359,14 @@ int import_from_file(FakeCore& simple_core, const std::string& import_file_path, str1.assign(buffer1, sizeof(chunk_size)); if (! ::serialization::parse_binary(str1, chunk_size)) { - throw tools::runtime_error("Error in deserialization of chunk size"); + throw std::runtime_error("Error in deserialization of chunk size"); } LOG_PRINT_L3("chunk_size: " << chunk_size); if (chunk_size > BUFFER_SIZE) { LOG_PRINT_L0("WARNING: chunk_size " << chunk_size << " > BUFFER_SIZE " << BUFFER_SIZE); - throw tools::runtime_error("Aborting: chunk size exceeds buffer size"); + throw std::runtime_error("Aborting: chunk size exceeds buffer size"); } if (chunk_size > 100000) { @@ -406,7 +406,7 @@ int import_from_file(FakeCore& simple_core, const std::string& import_file_path, str1.assign(buffer_block, chunk_size); bootstrap::block_package bp; if (! ::serialization::parse_binary(str1, bp)) - throw tools::runtime_error("Error in deserialization of chunk"); + throw std::runtime_error("Error in deserialization of chunk"); int display_interval = 1000; int progress_interval = 10; diff --git a/src/blockchain_utilities/bootstrap_file.cpp b/src/blockchain_utilities/bootstrap_file.cpp index 247709f57..da3b44593 100644 --- a/src/blockchain_utilities/bootstrap_file.cpp +++ b/src/blockchain_utilities/bootstrap_file.cpp @@ -117,7 +117,7 @@ bool BootstrapFile::initialize_file() std::string blob; if (! ::serialization::dump_binary(file_magic, blob)) { - throw tools::runtime_error("Error in serialization of file magic"); + throw std::runtime_error("Error in serialization of file magic"); } *m_raw_data_file << blob; @@ -143,7 +143,7 @@ bool BootstrapFile::initialize_file() if (! ::serialization::dump_binary(bd_size, blob)) { - throw tools::runtime_error("Error in serialization of bootstrap::file_info size"); + throw std::runtime_error("Error in serialization of bootstrap::file_info size"); } *output_stream_header << blob; *output_stream_header << bd; @@ -154,7 +154,7 @@ bool BootstrapFile::initialize_file() if (! ::serialization::dump_binary(bd_size, blob)) { - throw tools::runtime_error("Error in serialization of bootstrap::blocks_info size"); + throw std::runtime_error("Error in serialization of bootstrap::blocks_info size"); } *output_stream_header << blob; *output_stream_header << bd; @@ -181,7 +181,7 @@ void BootstrapFile::flush_chunk() std::string blob; if (! ::serialization::dump_binary(chunk_size, blob)) { - throw tools::runtime_error("Error in serialization of chunk size"); + throw std::runtime_error("Error in serialization of chunk size"); } *m_raw_data_file << blob; @@ -197,7 +197,7 @@ void BootstrapFile::flush_chunk() if (static_cast(num_chars_written) != chunk_size) { LOG_PRINT_RED_L0("Error writing chunk: height: " << m_cur_height << " chunk_size: " << chunk_size << " num chars written: " << num_chars_written); - throw tools::runtime_error("Error writing chunk"); + throw std::runtime_error("Error writing chunk"); } m_buffer.clear(); @@ -221,7 +221,7 @@ void BootstrapFile::write_block(block& block) { if (tx_id == null_hash) { - throw tools::runtime_error("Aborting: tx == null_hash"); + throw std::runtime_error("Aborting: tx == null_hash"); } #if SOURCE_DB == DB_MEMORY const transaction* tx = m_blockchain_storage->get_tx(tx_id); @@ -233,14 +233,14 @@ void BootstrapFile::write_block(block& block) if(tx == NULL) { if (! m_tx_pool) - throw tools::runtime_error("Aborting: tx == NULL, so memory pool required to get tx, but memory pool isn't enabled"); + throw std::runtime_error("Aborting: tx == NULL, so memory pool required to get tx, but memory pool isn't enabled"); else { transaction tx; if(m_tx_pool->get_transaction(tx_id, tx)) txs.push_back(tx); else - throw tools::runtime_error("Aborting: tx not found in pool"); + throw std::runtime_error("Aborting: tx not found in pool"); } } else @@ -362,16 +362,16 @@ uint64_t BootstrapFile::seek_to_first_chunk(std::ifstream& import_file) char buf1[2048]; import_file.read(buf1, sizeof(file_magic)); if (! import_file) - throw tools::runtime_error("Error reading expected number of bytes"); + throw std::runtime_error("Error reading expected number of bytes"); str1.assign(buf1, sizeof(file_magic)); if (! ::serialization::parse_binary(str1, file_magic)) - throw tools::runtime_error("Error in deserialization of file_magic"); + throw std::runtime_error("Error in deserialization of file_magic"); if (file_magic != blockchain_raw_magic) { LOG_PRINT_RED_L0("bootstrap file not recognized"); - throw tools::runtime_error("Aborting"); + throw std::runtime_error("Aborting"); } else LOG_PRINT_L0("bootstrap file recognized"); @@ -381,20 +381,20 @@ uint64_t BootstrapFile::seek_to_first_chunk(std::ifstream& import_file) import_file.read(buf1, sizeof(buflen_file_info)); str1.assign(buf1, sizeof(buflen_file_info)); if (! import_file) - throw tools::runtime_error("Error reading expected number of bytes"); + throw std::runtime_error("Error reading expected number of bytes"); if (! ::serialization::parse_binary(str1, buflen_file_info)) - throw tools::runtime_error("Error in deserialization of buflen_file_info"); + throw std::runtime_error("Error in deserialization of buflen_file_info"); LOG_PRINT_L1("bootstrap::file_info size: " << buflen_file_info); if (buflen_file_info > sizeof(buf1)) - throw tools::runtime_error("Error: bootstrap::file_info size exceeds buffer size"); + throw std::runtime_error("Error: bootstrap::file_info size exceeds buffer size"); import_file.read(buf1, buflen_file_info); if (! import_file) - throw tools::runtime_error("Error reading expected number of bytes"); + throw std::runtime_error("Error reading expected number of bytes"); str1.assign(buf1, buflen_file_info); bootstrap::file_info bfi; if (! ::serialization::parse_binary(str1, bfi)) - throw tools::runtime_error("Error in deserialization of bootstrap::file_info"); + throw std::runtime_error("Error in deserialization of bootstrap::file_info"); LOG_PRINT_L0("bootstrap file v" << unsigned(bfi.major_version) << "." << unsigned(bfi.minor_version)); LOG_PRINT_L0("bootstrap magic size: " << sizeof(file_magic)); LOG_PRINT_L0("bootstrap header size: " << bfi.header_size); @@ -412,7 +412,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) if (!boost::filesystem::exists(raw_file_path, ec)) { LOG_PRINT_L0("bootstrap file not found: " << raw_file_path); - throw tools::runtime_error("Aborting"); + throw std::runtime_error("Aborting"); } std::ifstream import_file; import_file.open(import_file_path, std::ios_base::binary | std::ifstream::in); @@ -421,7 +421,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) if (import_file.fail()) { LOG_PRINT_L0("import_file.open() fail"); - throw tools::runtime_error("Aborting"); + throw std::runtime_error("Aborting"); } uint64_t full_header_size; // 4 byte magic + length of header structures @@ -456,7 +456,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) str1.assign(buf1, sizeof(chunk_size)); if (! ::serialization::parse_binary(str1, chunk_size)) - throw tools::runtime_error("Error in deserialization of chunk_size"); + throw std::runtime_error("Error in deserialization of chunk_size"); LOG_PRINT_L3("chunk_size: " << chunk_size); if (chunk_size > BUFFER_SIZE) @@ -464,7 +464,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) std::cout << refresh_string; LOG_PRINT_L0("WARNING: chunk_size " << chunk_size << " > BUFFER_SIZE " << BUFFER_SIZE << " height: " << h-1); - throw tools::runtime_error("Aborting: chunk size exceeds buffer size"); + throw std::runtime_error("Aborting: chunk size exceeds buffer size"); } if (chunk_size > 100000) { @@ -475,7 +475,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) else if (chunk_size <= 0) { std::cout << refresh_string; LOG_PRINT_L0("ERROR: chunk_size " << chunk_size << " <= 0" << " height: " << h-1); - throw tools::runtime_error("Aborting"); + throw std::runtime_error("Aborting"); } // skip to next expected block size value import_file.seekg(chunk_size, std::ios_base::cur); @@ -483,7 +483,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) std::cout << refresh_string; LOG_PRINT_L0("ERROR: unexpected end of file: bytes read before error: " << import_file.gcount() << " of chunk_size " << chunk_size); - throw tools::runtime_error("Aborting"); + throw std::runtime_error("Aborting"); } bytes_read += chunk_size; diff --git a/src/blockchain_utilities/fake_core.h b/src/blockchain_utilities/fake_core.h index 3840a1c13..2fb5031d3 100644 --- a/src/blockchain_utilities/fake_core.h +++ b/src/blockchain_utilities/fake_core.h @@ -78,7 +78,7 @@ struct fake_core_db else { LOG_ERROR("Attempted to use non-existent database type: " << db_type); - throw tools::runtime_error("Attempting to use non-existent database type"); + throw std::runtime_error("Attempting to use non-existent database type"); } boost::filesystem::path folder(path); @@ -176,7 +176,7 @@ struct fake_core_memory { // TODO: // would need to refactor handle_block_to_main_chain() to have a direct add_block() method like Blockchain class - throw tools::runtime_error("direct add_block() method not implemented for in-memory db"); + throw std::runtime_error("direct add_block() method not implemented for in-memory db"); return 2; } diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 5537900ae..2289704e5 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -31,7 +31,6 @@ set(common_sources command_line.cpp dns_utils.cpp util.cpp - exception.cpp i18n.cpp) set(common_headers) @@ -49,7 +48,6 @@ set(common_private_headers unordered_containers_boost_serialization.h util.h varint.h - exception.h i18n.h) bitmonero_private_headers(common @@ -62,7 +60,6 @@ target_link_libraries(common LINK_PRIVATE crypto ${UNBOUND_LIBRARY} - ${LIBUNWIND_LIBRARIES} ${Boost_DATE_TIME_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} diff --git a/src/common/exception.cpp b/src/common/exception.cpp deleted file mode 100644 index f8954329f..000000000 --- a/src/common/exception.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2016, The Monero Project -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other -// materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be -// used to endorse or promote products derived from this software without specific -// prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "common/exception.h" -#include "misc_log_ex.h" -#define UNW_LOCAL_ONLY -#include -#include - -namespace tools -{ - -void log_stack_trace(const char *msg) -{ -#ifdef HAVE_LIBUNWIND - unw_context_t ctx; - unw_cursor_t cur; - unw_word_t ip, off; - unsigned level; - char sym[512], *dsym; - int status; - - if (msg) - LOG_PRINT_L0(msg); - LOG_PRINT_L0("Unwinded call stack:"); - if (unw_getcontext(&ctx) < 0) { - LOG_PRINT_L0("Failed to create unwind context"); - return; - } - if (unw_init_local(&cur, &ctx) < 0) { - LOG_PRINT_L0("Failed to find the first unwind frame"); - return; - } - for (level = 1; level < 999; ++level) { // 999 for safety - int ret = unw_step(&cur); - if (ret < 0) { - LOG_PRINT_L0("Failed to find the next frame"); - return; - } - if (ret == 0) - break; - if (unw_get_reg(&cur, UNW_REG_IP, &ip) < 0) { - LOG_PRINT_L0(" " << std::setw(4) << level); - continue; - } - if (unw_get_proc_name(&cur, sym, sizeof(sym), &off) < 0) { - LOG_PRINT_L0(" " << std::setw(4) << level << std::setbase(16) << std::setw(20) << "0x" << ip); - continue; - } - dsym = abi::__cxa_demangle(sym, NULL, NULL, &status); - LOG_PRINT_L0(" " << std::setw(4) << level << std::setbase(16) << std::setw(20) << "0x" << ip << " " << (!status && dsym ? dsym : sym) << " + " << "0x" << off); - free(dsym); - } -#else -#warning libunwind disabled, no stack traces -#endif -} - -} // namespace tools diff --git a/src/common/exception.h b/src/common/exception.h deleted file mode 100644 index 93e0d4013..000000000 --- a/src/common/exception.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2016, The Monero Project -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other -// materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be -// used to endorse or promote products derived from this software without specific -// prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef MONERO_EXCEPTION_H -#define MONERO_EXCEPTION_H - -#include -#include - -namespace tools -{ - -void log_stack_trace(const char *msg); - -class exception: public std::exception { -public: - exception() { log_stack_trace(what()); } -}; - -class runtime_error: public std::runtime_error { -public: - explicit runtime_error(const std::string &s): std::runtime_error(s) { log_stack_trace(what()); } - explicit runtime_error(const char *s): std::runtime_error(s) { log_stack_trace(what()); } -}; - -} // namespace tools - -#endif diff --git a/src/cryptonote_core/blockchain_storage.h b/src/cryptonote_core/blockchain_storage.h index e25f80116..878202cf1 100644 --- a/src/cryptonote_core/blockchain_storage.h +++ b/src/cryptonote_core/blockchain_storage.h @@ -41,7 +41,6 @@ #include "syncobj.h" #include "string_tools.h" -#include "common/exception.h" #include "tx_pool.h" #include "cryptonote_basic.h" #include "common/util.h" @@ -315,7 +314,7 @@ namespace cryptonote "m_invalid_blocks: " << m_invalid_blocks.size() << ENDL << "m_current_block_cumul_sz_limit: " << m_current_block_cumul_sz_limit); - throw tools::runtime_error("Blockchain data corruption"); + throw std::runtime_error("Blockchain data corruption"); } } } diff --git a/src/cryptonote_core/checkpoints_create.cpp b/src/cryptonote_core/checkpoints_create.cpp index 41246e8d8..41f2321d5 100644 --- a/src/cryptonote_core/checkpoints_create.cpp +++ b/src/cryptonote_core/checkpoints_create.cpp @@ -28,7 +28,6 @@ // // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers -#include "common/exception.h" #include "checkpoints_create.h" #include "common/dns_utils.h" #include "include_base_utils.h" diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 907f9d803..6f0fe88a4 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -161,7 +161,7 @@ namespace cryptonote cryptonote::checkpoints checkpoints; if (!cryptonote::create_checkpoints(checkpoints)) { - throw tools::runtime_error("Failed to initialize checkpoints"); + throw std::runtime_error("Failed to initialize checkpoints"); } set_checkpoints(std::move(checkpoints)); diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index 186c1c93b..32f0b2ad4 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -36,7 +36,6 @@ #include #include -#include #include "p2p/net_node_common.h" #include "cryptonote_protocol/cryptonote_protocol_handler_common.h" #include "storages/portable_storage_template_helper.h" diff --git a/src/cryptonote_core/miner.cpp b/src/cryptonote_core/miner.cpp index 7bc126cd8..bad3f30bd 100644 --- a/src/cryptonote_core/miner.cpp +++ b/src/cryptonote_core/miner.cpp @@ -34,7 +34,6 @@ #include #include #include -#include "common/exception.h" #include "misc_language.h" #include "include_base_utils.h" #include "cryptonote_basic_impl.h" diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h index 2112b5082..1c92958c9 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.h +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h @@ -38,7 +38,6 @@ #include #include -#include "common/exception.h" #include "storages/levin_abstract_invoke2.h" #include "warnings.h" #include "cryptonote_protocol_defs.h" diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp index c48b836e9..0b42257e7 100644 --- a/src/daemon/command_parser_executor.cpp +++ b/src/daemon/command_parser_executor.cpp @@ -26,7 +26,6 @@ // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "common/exception.h" #include "cryptonote_core/cryptonote_basic_impl.h" #include "daemon/command_parser_executor.h" diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp index 7e5139636..206de9d4a 100644 --- a/src/daemon/command_server.cpp +++ b/src/daemon/command_server.cpp @@ -26,7 +26,6 @@ // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "common/exception.h" #include "cryptonote_config.h" #include "version.h" #include "daemon/command_server.h" diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index d44538358..e79823d08 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -110,7 +110,7 @@ bool t_daemon::run(bool interactive) { if (nullptr == mp_internals) { - throw tools::runtime_error{"Can't run stopped daemon"}; + throw std::runtime_error{"Can't run stopped daemon"}; } tools::signal_handler::install(std::bind(&daemonize::t_daemon::stop_p2p, this)); @@ -155,7 +155,7 @@ void t_daemon::stop() { if (nullptr == mp_internals) { - throw tools::runtime_error{"Can't stop stopped daemon"}; + throw std::runtime_error{"Can't stop stopped daemon"}; } mp_internals->p2p.stop(); mp_internals->rpc.stop(); @@ -166,7 +166,7 @@ void t_daemon::stop_p2p() { if (nullptr == mp_internals) { - throw tools::runtime_error{"Can't send stop signal to a stopped daemon"}; + throw std::runtime_error{"Can't send stop signal to a stopped daemon"}; } mp_internals->p2p.get().send_stop_signal(); } diff --git a/src/daemon/p2p.h b/src/daemon/p2p.h index b74a5e72d..3858989ce 100644 --- a/src/daemon/p2p.h +++ b/src/daemon/p2p.h @@ -60,7 +60,7 @@ public: LOG_PRINT_L0("Initializing p2p server..."); if (!m_server.init(vm)) { - throw tools::runtime_error("Failed to initialize p2p server."); + throw std::runtime_error("Failed to initialize p2p server."); } LOG_PRINT_L0("P2p server initialized OK"); } diff --git a/src/daemon/protocol.h b/src/daemon/protocol.h index 5f6c317b1..8e2add4a2 100644 --- a/src/daemon/protocol.h +++ b/src/daemon/protocol.h @@ -50,7 +50,7 @@ public: LOG_PRINT_L0("Initializing cryptonote protocol..."); if (!m_protocol.init(vm)) { - throw tools::runtime_error("Failed to initialize cryptonote protocol."); + throw std::runtime_error("Failed to initialize cryptonote protocol."); } LOG_PRINT_L0("Cryptonote protocol initialized OK"); } diff --git a/src/daemon/rpc.h b/src/daemon/rpc.h index caeae9a3d..bfd2afd84 100644 --- a/src/daemon/rpc.h +++ b/src/daemon/rpc.h @@ -55,7 +55,7 @@ public: LOG_PRINT_L0("Initializing core rpc server..."); if (!m_server.init(vm)) { - throw tools::runtime_error("Failed to initialize core rpc server."); + throw std::runtime_error("Failed to initialize core rpc server."); } LOG_PRINT_GREEN("Core rpc server initialized OK on port: " << m_server.get_binded_port(), LOG_LEVEL_0); } @@ -65,7 +65,7 @@ public: LOG_PRINT_L0("Starting core rpc server..."); if (!m_server.run(2, false)) { - throw tools::runtime_error("Failed to start core rpc server."); + throw std::runtime_error("Failed to start core rpc server."); } LOG_PRINT_L0("Core rpc server started ok"); } diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index b57c60948..15ddc081f 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -28,7 +28,6 @@ // // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers -#include "common/exception.h" #include "string_tools.h" #include "common/scoped_message_writer.h" #include "daemon/rpc_command_executor.h" @@ -89,7 +88,7 @@ t_rpc_command_executor::t_rpc_command_executor( { if (rpc_server == NULL) { - throw tools::runtime_error("If not calling commands via RPC, rpc_server pointer must be non-null"); + throw std::runtime_error("If not calling commands via RPC, rpc_server pointer must be non-null"); } } diff --git a/src/daemonizer/posix_fork.cpp b/src/daemonizer/posix_fork.cpp index 84ff88869..c068912ec 100644 --- a/src/daemonizer/posix_fork.cpp +++ b/src/daemonizer/posix_fork.cpp @@ -4,7 +4,6 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#include "common/exception.h" #include "daemonizer/posix_fork.h" #include "misc_log_ex.h" @@ -21,7 +20,7 @@ namespace { void quit(std::string const & message) { LOG_ERROR(message); - throw tools::runtime_error(message); + throw std::runtime_error(message); } } diff --git a/src/miner/simpleminer.cpp b/src/miner/simpleminer.cpp index 19db3f534..ba956d90b 100644 --- a/src/miner/simpleminer.cpp +++ b/src/miner/simpleminer.cpp @@ -28,7 +28,6 @@ // // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers -#include "common/exception.h" #include "common/command_line.h" #include "misc_log_ex.h" #include "simpleminer.h" diff --git a/src/p2p/data_logger.cpp b/src/p2p/data_logger.cpp index d3ff0ca8e..ca0726c5f 100644 --- a/src/p2p/data_logger.cpp +++ b/src/p2p/data_logger.cpp @@ -33,7 +33,6 @@ #include #include #include -#include "common/exception.h" #include "../../contrib/otshell_utils/utils.hpp" namespace epee @@ -44,7 +43,7 @@ namespace net_utils boost::call_once(m_singleton, [] { _info_c("dbg/data","Creating singleton of data_logger"); - if (m_state != data_logger_state::state_before_init) { _erro_c("dbg/data","Internal error in singleton"); throw tools::runtime_error("data_logger singleton"); } + if (m_state != data_logger_state::state_before_init) { _erro_c("dbg/data","Internal error in singleton"); throw std::runtime_error("data_logger singleton"); } m_state = data_logger_state::state_during_init; m_obj.reset(new data_logger()); m_state = data_logger_state::state_ready_to_use; @@ -53,7 +52,7 @@ namespace net_utils if (m_state != data_logger_state::state_ready_to_use) { _erro ("trying to use not working data_logger"); - throw tools::runtime_error("data_logger ctor state"); + throw std::runtime_error("data_logger ctor state"); } return * m_obj; @@ -61,7 +60,7 @@ namespace net_utils data_logger::data_logger() { _note_c("dbg/data","Starting data logger (for graphs data)"); - if (m_state != data_logger_state::state_during_init) { _erro_c("dbg/data","Singleton ctor state"); throw tools::runtime_error("data_logger ctor state"); } + if (m_state != data_logger_state::state_during_init) { _erro_c("dbg/data","Singleton ctor state"); throw std::runtime_error("data_logger ctor state"); } boost::lock_guard lock(mMutex); // lock // prepare all the files for given data channels: diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index eb12f52ed..ea1993c80 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -561,7 +561,7 @@ bool simple_wallet::set_variable(const std::vector &args) { if (args.empty()) { - fail_msg_writer() << tr("set: needs an argument. available options: seed, always-confirm-transfers, store-tx-info, default-mixin, auto-refresh, refresh-type"); + fail_msg_writer() << tr("set: needs an argument. available options: seed, always-confirm-transfers, default-mixin, auto-refresh, refresh-type"); return true; } else diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index ef17a770b..2afe08cb1 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -32,7 +32,6 @@ #include #include -#include "common/exception.h" #include "include_base_utils.h" using namespace epee; @@ -804,7 +803,7 @@ void wallet2::refresh(uint64_t start_height, uint64_t & blocks_fetched, bool& re // handle error from async fetching thread if (error) { - throw tools::runtime_error("proxy exception in refresh thread"); + throw std::runtime_error("proxy exception in refresh thread"); } } catch (const std::exception&) @@ -2013,7 +2012,7 @@ std::vector wallet2::create_transactions(std::vector ptx_vector; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 0961ad981..f798f404d 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -35,7 +35,6 @@ #include #include -#include "common/exception.h" #include "include_base_utils.h" #include "cryptonote_core/account.h" #include "cryptonote_core/account_boost_serialization.h" diff --git a/src/wallet/wallet2_api.cpp b/src/wallet/wallet2_api.cpp index 0cb253398..0644e3690 100644 --- a/src/wallet/wallet2_api.cpp +++ b/src/wallet/wallet2_api.cpp @@ -28,7 +28,6 @@ // // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers -#include "common/exception.h" #include "wallet2_api.h" #include "wallet2.h" #include "mnemonics/electrum-words.h" diff --git a/tests/core_proxy/core_proxy.h b/tests/core_proxy/core_proxy.h index 22f4c0421..0315fc8c8 100644 --- a/tests/core_proxy/core_proxy.h +++ b/tests/core_proxy/core_proxy.h @@ -82,7 +82,7 @@ namespace tests bool on_idle(){return true;} bool find_blockchain_supplement(const std::list& qblock_ids, cryptonote::NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp){return true;} bool handle_get_objects(cryptonote::NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote::NOTIFY_RESPONSE_GET_OBJECTS::request& rsp, cryptonote::cryptonote_connection_context& context){return true;} - cryptonote::blockchain_storage &get_blockchain_storage() { throw tools::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class proxy_core."); } + cryptonote::blockchain_storage &get_blockchain_storage() { throw std::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class proxy_core."); } bool get_test_drop_download() {return true;} bool get_test_drop_download_height() {return true;} bool prepare_handle_incoming_blocks(const std::list &blocks) { return true; } diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index b897d9237..4fdd0a600 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -58,7 +58,7 @@ void test_generator::get_block_chain(std::vector& blockchain, const auto it = m_blocks_info.find(curr); if (m_blocks_info.end() == it) { - throw tools::runtime_error("block hash wasn't found"); + throw std::runtime_error("block hash wasn't found"); } blockchain.push_back(it->second); @@ -82,7 +82,7 @@ uint64_t test_generator::get_already_generated_coins(const crypto::hash& blk_id) { auto it = m_blocks_info.find(blk_id); if (it == m_blocks_info.end()) - throw tools::runtime_error("block hash wasn't found"); + throw std::runtime_error("block hash wasn't found"); return it->second.already_generated_coins; } @@ -323,7 +323,7 @@ bool init_output_indices(map_output_idx_t& outs, std::mapsecond); } @@ -486,11 +486,11 @@ void fill_tx_sources_and_destinations(const std::vector& event destinations.clear(); if (!fill_tx_sources(sources, events, blk_head, from, amount + fee, nmix)) - throw tools::runtime_error("couldn't fill transaction sources"); + throw std::runtime_error("couldn't fill transaction sources"); tx_destination_entry de; if (!fill_tx_destination(de, to, amount)) - throw tools::runtime_error("couldn't fill transaction destination"); + throw std::runtime_error("couldn't fill transaction destination"); destinations.push_back(de); tx_destination_entry de_change; @@ -498,7 +498,7 @@ void fill_tx_sources_and_destinations(const std::vector& event if (0 < cache_back) { if (!fill_tx_destination(de_change, from, cache_back)) - throw tools::runtime_error("couldn't fill transaction cache back destination"); + throw std::runtime_error("couldn't fill transaction cache back destination"); destinations.push_back(de_change); } } diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index d51d9d320..d0d912cbb 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -284,7 +284,7 @@ bool do_check_tx_verification_context(const cryptonote::tx_verification_context& { // Default block verification context check if (tvc.m_verifivation_failed) - throw tools::runtime_error("Transaction verification failed"); + throw std::runtime_error("Transaction verification failed"); return true; } //-------------------------------------------------------------------------- @@ -307,7 +307,7 @@ bool do_check_block_verification_context(const cryptonote::block_verification_co { // Default block verification context check if (bvc.m_verifivation_failed) - throw tools::runtime_error("Block verification failed"); + throw std::runtime_error("Block verification failed"); return true; } //-------------------------------------------------------------------------- @@ -621,7 +621,7 @@ inline bool do_replay_file(const std::string& filename) if (!tools::serialize_obj_to_file(events, filename)) \ { \ std::cout << concolor::magenta << "Failed to serialize data to file: " << filename << concolor::normal << std::endl; \ - throw tools::runtime_error("Failed to serialize data to file"); \ + throw std::runtime_error("Failed to serialize data to file"); \ } \ } diff --git a/tests/core_tests/tx_validation.cpp b/tests/core_tests/tx_validation.cpp index 41d5f1e26..f72c906e5 100644 --- a/tests/core_tests/tx_validation.cpp +++ b/tests/core_tests/tx_validation.cpp @@ -156,7 +156,7 @@ namespace } } - throw tools::runtime_error("invalid public key wasn't found"); + throw std::runtime_error("invalid public key wasn't found"); return crypto::public_key(); } } diff --git a/tests/net_load_tests/clt.cpp b/tests/net_load_tests/clt.cpp index 360261676..56089a4da 100644 --- a/tests/net_load_tests/clt.cpp +++ b/tests/net_load_tests/clt.cpp @@ -37,7 +37,6 @@ #include "gtest/gtest.h" -#include "common/exception.h" #include "include_base_utils.h" #include "misc_language.h" #include "misc_log_ex.h" diff --git a/tests/net_load_tests/srv.cpp b/tests/net_load_tests/srv.cpp index 13b31215e..d8d3eae2e 100644 --- a/tests/net_load_tests/srv.cpp +++ b/tests/net_load_tests/srv.cpp @@ -31,7 +31,6 @@ #include #include -#include "common/exception.h" #include "include_base_utils.h" #include "misc_log_ex.h" #include "storages/levin_abstract_invoke2.h" diff --git a/tests/unit_tests/ban.cpp b/tests/unit_tests/ban.cpp index 5d40e90cf..a5ce244d9 100644 --- a/tests/unit_tests/ban.cpp +++ b/tests/unit_tests/ban.cpp @@ -56,7 +56,7 @@ public: bool on_idle(){return true;} bool find_blockchain_supplement(const std::list& qblock_ids, cryptonote::NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp){return true;} bool handle_get_objects(cryptonote::NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote::NOTIFY_RESPONSE_GET_OBJECTS::request& rsp, cryptonote::cryptonote_connection_context& context){return true;} - cryptonote::blockchain_storage &get_blockchain_storage() { throw tools::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class test_core."); } + cryptonote::blockchain_storage &get_blockchain_storage() { throw std::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class test_core."); } bool get_test_drop_download() const {return true;} bool get_test_drop_download_height() const {return true;} bool prepare_handle_incoming_blocks(const std::list &blocks) { return true; } diff --git a/tests/unit_tests/epee_boosted_tcp_server.cpp b/tests/unit_tests/epee_boosted_tcp_server.cpp index b68ce77bb..946db292d 100644 --- a/tests/unit_tests/epee_boosted_tcp_server.cpp +++ b/tests/unit_tests/epee_boosted_tcp_server.cpp @@ -104,7 +104,7 @@ TEST(boosted_tcp_server, worker_threads_are_exception_resistant) // 2 theads, but 4 exceptions ASSERT_TRUE(srv.run_server(2, false)); - ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw tools::runtime_error("test 1"); })); + ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw std::runtime_error("test 1"); })); ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw std::string("test 2"); })); ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw "test 3"; })); ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw 4; })); diff --git a/tests/unit_tests/mnemonics.cpp b/tests/unit_tests/mnemonics.cpp index 3bf1df7ed..3dc5db7d4 100644 --- a/tests/unit_tests/mnemonics.cpp +++ b/tests/unit_tests/mnemonics.cpp @@ -27,7 +27,6 @@ // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "gtest/gtest.h" -#include "common/exception.h" #include "mnemonics/electrum-words.h" #include "crypto/crypto.h" #include diff --git a/tests/unit_tests/test_protocol_pack.cpp b/tests/unit_tests/test_protocol_pack.cpp index 1ff70b4d9..a9a1a34a6 100644 --- a/tests/unit_tests/test_protocol_pack.cpp +++ b/tests/unit_tests/test_protocol_pack.cpp @@ -30,7 +30,6 @@ #include "gtest/gtest.h" -#include "common/exception.h" #include "include_base_utils.h" #include "cryptonote_protocol/cryptonote_protocol_defs.h" #include "storages/portable_storage_template_helper.h" -- cgit v1.2.3 From a2e378b91bf5d2a54284f8e20df5080f11d25ff6 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Fri, 25 Mar 2016 00:48:11 +0000 Subject: wallet: add a --generate-from-json flag It takes a filename containing JSON data to generate a wallet. The following fields are valid: version: integer, should be 1 filename: string, path/filename for the newly created wallet scan_from_height: 64 bit unsigned integer, optional password: string, optional viewkey: string, hex representation spendkey: string, hex representation seed: string, optional, list of words separated by spaces Either seed or private keys should be given. If using private keys, the spend key may be omitted (the wallet will not be able to spend, but will see incoming transactions). If scan_from_height is given, blocks below this height will not be checked for transactions as an optimization. --- src/simplewallet/simplewallet.cpp | 186 ++++++++++++++++++++++++++++++++++++-- src/simplewallet/simplewallet.h | 2 + src/wallet/wallet2.cpp | 2 +- src/wallet/wallet2.h | 12 ++- 4 files changed, 192 insertions(+), 10 deletions(-) (limited to 'src/wallet/wallet2.cpp') diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index ea1993c80..1856118f7 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -57,6 +57,7 @@ #include "version.h" #include "crypto/crypto.h" // for crypto::secret_key definition #include "mnemonics/electrum-words.h" +#include "rapidjson/document.h" #include #if defined(WIN32) @@ -81,6 +82,7 @@ namespace const command_line::arg_descriptor arg_generate_new_wallet = {"generate-new-wallet", sw::tr("Generate new wallet and save it to or
.wallet by default"), ""}; const command_line::arg_descriptor arg_generate_from_view_key = {"generate-from-view-key", sw::tr("Generate incoming-only wallet from view key"), ""}; const command_line::arg_descriptor arg_generate_from_keys = {"generate-from-keys", sw::tr("Generate wallet from private keys"), ""}; + const command_line::arg_descriptor arg_generate_from_json = {"generate-from-json", sw::tr("Generate wallet from JSON format file"), ""}; const command_line::arg_descriptor arg_daemon_address = {"daemon-address", sw::tr("Use daemon instance at :"), ""}; const command_line::arg_descriptor arg_daemon_host = {"daemon-host", sw::tr("Use daemon instance at host instead of localhost"), ""}; const command_line::arg_descriptor arg_password = {"password", sw::tr("Wallet password"), "", true}; @@ -716,7 +718,7 @@ bool simple_wallet::ask_wallet_create_if_needed() // add logic to error out if new wallet requested but named wallet file exists if (keys_file_exists || wallet_file_exists) { - if (!m_generate_new.empty() || m_restore_deterministic_wallet || !m_generate_from_view_key.empty() || !m_generate_from_keys.empty()) + if (!m_generate_new.empty() || m_restore_deterministic_wallet || !m_generate_from_view_key.empty() || !m_generate_from_keys.empty() || !m_generate_from_json.empty()) { fail_msg_writer() << tr("attempting to generate or restore wallet, but specified file(s) exist. Exiting to not risk overwriting."); return false; @@ -763,6 +765,13 @@ void simple_wallet::print_seed(std::string seed) //---------------------------------------------------------------------------------------------------- static bool get_password(const boost::program_options::variables_map& vm, bool allow_entry, tools::password_container &pwd_container) { + // has_arg returns true even when the parameter is not passed ?? + const std::string gfj = command_line::get_arg(vm, arg_generate_from_json); + if (!gfj.empty()) { + // will be in the json file, if any + return true; + } + if (has_arg(vm, arg_password) && has_arg(vm, arg_password_file)) { fail_msg_writer() << tr("can't specify more than one of --password and --password-file"); @@ -808,6 +817,153 @@ static bool get_password(const boost::program_options::variables_map& vm, bool a return false; } +//---------------------------------------------------------------------------------------------------- +bool simple_wallet::generate_from_json(const boost::program_options::variables_map& vm, std::string &wallet_file, std::string &password) +{ + std::string buf; + bool r = epee::file_io_utils::load_file_to_string(m_generate_from_json, buf); + if (!r) { + fail_msg_writer() << tr("Failed to load file ") << m_generate_from_json; + return false; + } + + rapidjson::Document json; + if (json.Parse(buf.c_str()).HasParseError()) { + fail_msg_writer() << tr("Failed to parse JSON"); + return false; + } + + if (!json.HasMember("version")) { + fail_msg_writer() << tr("Version not found in JSON"); + return false; + } + unsigned int version = json["version"].GetUint(); + const int current_version = 1; + if (version > current_version) { + fail_msg_writer() << boost::format(tr("Version %u too new, we can only grok up to %u")) % version % current_version; + return false; + } + if (!json.HasMember("filename")) { + fail_msg_writer() << tr("Filename not found in JSON"); + return false; + } + std::string filename = json["filename"].GetString(); + + bool recover = false; + uint64_t scan_from_height = 0; + if (json.HasMember("scan_from_height")) { + scan_from_height = json["scan_from_height"].GetUint64(); + recover = true; + } + + password = ""; + if (json.HasMember("password")) { + password = json["password"].GetString(); + } + + std::string viewkey_string(""); + crypto::secret_key viewkey; + if (json.HasMember("viewkey")) { + viewkey_string = json["viewkey"].GetString(); + cryptonote::blobdata viewkey_data; + if(!epee::string_tools::parse_hexstr_to_binbuff(viewkey_string, viewkey_data)) + { + fail_msg_writer() << tr("failed to parse view key secret key"); + return false; + } + viewkey = *reinterpret_cast(viewkey_data.data()); + } + + std::string spendkey_string(""); + crypto::secret_key spendkey; + if (json.HasMember("spendkey")) { + spendkey_string = json["spendkey"].GetString(); + cryptonote::blobdata spendkey_data; + if(!epee::string_tools::parse_hexstr_to_binbuff(spendkey_string, spendkey_data)) + { + fail_msg_writer() << tr("failed to parse spend key secret key"); + return false; + } + spendkey = *reinterpret_cast(spendkey_data.data()); + } + + std::string seed(""); + std::string old_language; + if (json.HasMember("seed")) { + seed = json["seed"].GetString(); + if (!crypto::ElectrumWords::words_to_bytes(seed, m_recovery_key, old_language)) + { + fail_msg_writer() << tr("Electrum-style word list failed verification"); + return false; + } + m_electrum_seed = seed; + m_restore_deterministic_wallet = true; + } + + // compatibility checks + if (seed.empty() && viewkey_string.empty()) { + fail_msg_writer() << tr("At least one of Electrum-style word list and private view key must be specified"); + return false; + } + if (!seed.empty() && (!viewkey_string.empty() || !spendkey_string.empty())) { + fail_msg_writer() << tr("Both Electrum-style word list and private key(s) specified"); + return false; + } + + m_wallet_file = filename; + + bool was_deprecated_wallet = m_restore_deterministic_wallet && ((old_language == crypto::ElectrumWords::old_language_name) || + crypto::ElectrumWords::get_is_old_style_seed(m_electrum_seed)); + if (was_deprecated_wallet) { + fail_msg_writer() << tr("Cannot create deprecated wallets from JSON"); + return false; + } + + bool testnet = command_line::get_arg(vm, arg_testnet); + m_wallet.reset(new tools::wallet2(testnet)); + m_wallet->callback(this); + + try + { + if (!seed.empty()) + { + m_wallet->generate(m_wallet_file, password, m_recovery_key, recover, false); + } + else + { + cryptonote::account_public_address address; + if (!crypto::secret_key_to_public_key(viewkey, address.m_view_public_key)) { + fail_msg_writer() << tr("failed to verify view key secret key"); + return false; + } + if (!crypto::secret_key_to_public_key(spendkey, address.m_spend_public_key)) { + fail_msg_writer() << tr("failed to verify spend key secret key"); + return false; + } + + if (spendkey_string.empty()) + { + m_wallet->generate(m_wallet_file, password, address, viewkey); + } + else + { + m_wallet->generate(m_wallet_file, password, address, spendkey, viewkey); + } + } + } + catch (const std::exception& e) + { + fail_msg_writer() << tr("failed to generate new wallet: ") << e.what(); + return false; + } + + m_wallet->set_refresh_from_block_height(scan_from_height); + + wallet_file = m_wallet_file; + + return r; +} + //---------------------------------------------------------------------------------------------------- bool simple_wallet::init(const boost::program_options::variables_map& vm) { @@ -820,12 +976,12 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) return false; } - if((!m_generate_new.empty()) + (!m_wallet_file.empty()) + (!m_generate_from_view_key.empty()) + (!m_generate_from_keys.empty()) > 1) + if((!m_generate_new.empty()) + (!m_wallet_file.empty()) + (!m_generate_from_view_key.empty()) + (!m_generate_from_keys.empty()) + (!m_generate_from_json.empty()) > 1) { - fail_msg_writer() << tr("can't specify more than one of --generate-new-wallet=\"wallet_name\", --wallet-file=\"wallet_name\", --generate-from-view-key=\"wallet_name\" and --generate-from-keys=\"wallet_name\""); + fail_msg_writer() << tr("can't specify more than one of --generate-new-wallet=\"wallet_name\", --wallet-file=\"wallet_name\", --generate-from-view-key=\"wallet_name\", --generate-from-json=\"jsonfilename\" and --generate-from-keys=\"wallet_name\""); return false; } - else if (m_generate_new.empty() && m_wallet_file.empty() && m_generate_from_view_key.empty() && m_generate_from_keys.empty()) + else if (m_generate_new.empty() && m_wallet_file.empty() && m_generate_from_view_key.empty() && m_generate_from_keys.empty() && m_generate_from_json.empty()) { if(!ask_wallet_create_if_needed()) return false; } @@ -847,7 +1003,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) if (!get_password(vm, true, pwd_container)) return false; - if (!m_generate_new.empty() || m_restore_deterministic_wallet || !m_generate_from_view_key.empty() || !m_generate_from_keys.empty()) + if (!m_generate_new.empty() || m_restore_deterministic_wallet || !m_generate_from_view_key.empty() || !m_generate_from_keys.empty() || !m_generate_from_json.empty()) { if (m_wallet_file.empty()) m_wallet_file = m_generate_new; // alias for simplicity later @@ -993,6 +1149,12 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) bool r = new_wallet(m_wallet_file, pwd_container.password(), address, spendkey, viewkey, testnet); CHECK_AND_ASSERT_MES(r, false, tr("account creation failed")); } + else if (!m_generate_from_json.empty()) + { + std::string wallet_file, password; // we don't need to remember them + if (!generate_from_json(vm, wallet_file, password)) + return false; + } else { bool r = new_wallet(m_wallet_file, pwd_container.password(), m_recovery_key, m_restore_deterministic_wallet, @@ -1023,6 +1185,7 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_ m_generate_new = command_line::get_arg(vm, arg_generate_new_wallet); m_generate_from_view_key = command_line::get_arg(vm, arg_generate_from_view_key); m_generate_from_keys = command_line::get_arg(vm, arg_generate_from_keys); + m_generate_from_json = command_line::get_arg(vm, arg_generate_from_json); m_daemon_address = command_line::get_arg(vm, arg_daemon_address); m_daemon_host = command_line::get_arg(vm, arg_daemon_host); m_daemon_port = command_line::get_arg(vm, arg_daemon_port); @@ -2575,6 +2738,7 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_params, arg_generate_new_wallet); command_line::add_arg(desc_params, arg_generate_from_view_key); command_line::add_arg(desc_params, arg_generate_from_keys); + command_line::add_arg(desc_params, arg_generate_from_json); command_line::add_arg(desc_params, arg_password); command_line::add_arg(desc_params, arg_password_file); command_line::add_arg(desc_params, arg_daemon_address); @@ -2707,11 +2871,21 @@ int main(int argc, char* argv[]) if (daemon_address.empty()) daemon_address = std::string("http://") + daemon_host + ":" + std::to_string(daemon_port); + std::string password; + const std::string gfj = command_line::get_arg(vm, arg_generate_from_json); + if (!gfj.empty()) { + if (!w.generate_from_json(vm, wallet_file, password)) + return 1; + } + else { + password = pwd_container.password(); + } + tools::wallet2 wal(testnet,restricted); try { LOG_PRINT_L0(sw::tr("Loading wallet...")); - wal.load(wallet_file, pwd_container.password()); + wal.load(wallet_file, password); wal.init(daemon_address); wal.refresh(); LOG_PRINT_GREEN(sw::tr("Loaded ok"), LOG_LEVEL_0); diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index d1617dbf4..7dadb8536 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -69,6 +69,7 @@ namespace cryptonote bool run(); void stop(); void interrupt(); + bool generate_from_json(const boost::program_options::variables_map& vm, std::string &wallet_file, std::string &password); //wallet *create_wallet(); bool process_command(const std::vector &args); @@ -221,6 +222,7 @@ namespace cryptonote std::string m_generate_new; std::string m_generate_from_view_key; std::string m_generate_from_keys; + std::string m_generate_from_json; std::string m_import_path; std::string m_electrum_seed; // electrum-style seed parameter diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 2afe08cb1..1c7187cf0 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -490,7 +490,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry //handle transactions from new block //optimization: seeking only for blocks that are not older then the wallet creation time plus 1 day. 1 day is for possible user incorrect time setup - if(b.timestamp + 60*60*24 > m_account.get_createtime()) + if(b.timestamp + 60*60*24 > m_account.get_createtime() && height >= m_refresh_from_block_height) { TIME_MEASURE_START(miner_tx_handle_time); process_new_transaction(b.miner_tx, height, true); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index f798f404d..e7b002925 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -88,10 +88,10 @@ namespace tools }; private: - wallet2(const wallet2&) : m_run(true), m_callback(0), m_testnet(false), m_always_confirm_transfers (false), m_store_tx_info(true), m_default_mixin(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true) {} + wallet2(const wallet2&) : m_run(true), m_callback(0), m_testnet(false), m_always_confirm_transfers (false), m_store_tx_info(true), m_default_mixin(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0) {} public: - wallet2(bool testnet = false, bool restricted = false) : m_run(true), m_callback(0), m_testnet(testnet), m_restricted(restricted), is_old_file_format(false), m_store_tx_info(true), m_default_mixin(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true) {} + wallet2(bool testnet = false, bool restricted = false) : m_run(true), m_callback(0), m_testnet(testnet), m_restricted(restricted), is_old_file_format(false), m_store_tx_info(true), m_default_mixin(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0) {} struct transfer_details { uint64_t m_block_height; @@ -226,6 +226,8 @@ namespace tools cryptonote::account_base& get_account(){return m_account;} const cryptonote::account_base& get_account()const{return m_account;} + void set_refresh_from_block_height(uint64_t height) {m_refresh_from_block_height = height;} + // upper_transaction_size_limit as defined below is set to // approximately 125% of the fixed minimum allowable penalty // free block size. TODO: fix this so that it actually takes @@ -319,6 +321,9 @@ namespace tools if(ver < 9) return; a & m_confirmed_txs; + if(ver < 11) + return; + a & m_refresh_from_block_height; } /*! @@ -430,9 +435,10 @@ namespace tools uint32_t m_default_mixin; RefreshType m_refresh_type; bool m_auto_refresh; + uint64_t m_refresh_from_block_height; }; } -BOOST_CLASS_VERSION(tools::wallet2, 10) +BOOST_CLASS_VERSION(tools::wallet2, 11) BOOST_CLASS_VERSION(tools::wallet2::payment_details, 0) BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 2) BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 1) -- cgit v1.2.3 From f26651ab8a3ed7f39a13f258880ee57f7ab85b68 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 26 Mar 2016 11:44:43 +0000 Subject: wallet: factor fee calculation --- src/wallet/wallet2.cpp | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) (limited to 'src/wallet/wallet2.cpp') diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 1c7187cf0..7c54ca5e9 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -92,6 +92,13 @@ void do_prepare_file_names(const std::string& file_path, std::string& keys_file, } } +uint64_t calculate_fee(const cryptonote::blobdata &blob) +{ + uint64_t bytes = blob.size(); + uint64_t kB = (bytes + 1023) / 1024; + return kB * FEE_PER_KB; +} + } //namespace namespace tools @@ -2030,13 +2037,7 @@ std::vector wallet2::create_transactions(std::vector wallet2::create_transactions_2(std::vector available_for_fee && dsts[0].amount > 0) @@ -2686,13 +2681,7 @@ std::vector wallet2::create_dust_sweep_transactions() { transfer_dust(num_outputs_per_tx, (uint64_t)0 /* unlock_time */, 0, detail::digit_split_strategy, dust_policy, extra, tx, ptx); auto txBlob = t_serializable_object_to_blob(ptx.tx); - uint64_t txSize = txBlob.size(); - uint64_t numKB = txSize / 1024; - if (txSize % 1024) - { - numKB++; - } - needed_fee = numKB * FEE_PER_KB; + needed_fee = calculate_fee(txBlob); // reroll the tx with the actual amount minus the fee // if there's not enough for the fee, it'll throw -- cgit v1.2.3 From f9a2fd2ff55654cdbc458378d0365189ffd1c46a Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 26 Mar 2016 11:51:58 +0000 Subject: wallet: handle rare case where fee adjustment can bump to the next kB It resulted in a tx being sent with too low a fee, and thus rejected. --- src/wallet/wallet2.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/wallet/wallet2.cpp') diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 7c54ca5e9..aa638143c 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2677,7 +2677,7 @@ std::vector wallet2::create_dust_sweep_transactions() // loop until fee is met without increasing tx size to next KB boundary. uint64_t needed_fee = 0; - if (1) + do { transfer_dust(num_outputs_per_tx, (uint64_t)0 /* unlock_time */, 0, detail::digit_split_strategy, dust_policy, extra, tx, ptx); auto txBlob = t_serializable_object_to_blob(ptx.tx); @@ -2687,7 +2687,8 @@ std::vector wallet2::create_dust_sweep_transactions() // if there's not enough for the fee, it'll throw transfer_dust(num_outputs_per_tx, (uint64_t)0 /* unlock_time */, needed_fee, detail::digit_split_strategy, dust_policy, extra, tx, ptx); txBlob = t_serializable_object_to_blob(ptx.tx); - } + needed_fee = calculate_fee(txBlob); + } while (ptx.fee < needed_fee); ptx_vector.push_back(ptx); -- cgit v1.2.3 From 12146daeed66fc30319c481a378c8d317b49b4db Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 26 Mar 2016 21:15:47 +0000 Subject: wallet: change sweep_dust to sweep_unmixable With the change in mixin rules for v2, the "annoying" outputs are slightly changed. There is high correlation between dust and unmixable, but no equivalence. --- src/simplewallet/simplewallet.cpp | 35 ++++++++----- src/simplewallet/simplewallet.h | 2 +- src/wallet/wallet2.cpp | 104 +++++++++++++++++++++++++++++++++----- src/wallet/wallet2.h | 7 ++- src/wallet/wallet_errors.h | 9 ++++ src/wallet/wallet_rpc_server.cpp | 2 +- 6 files changed, 129 insertions(+), 30 deletions(-) (limited to 'src/wallet/wallet2.cpp') diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 1856118f7..dd166ede5 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -541,7 +541,7 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("bc_height", boost::bind(&simple_wallet::show_blockchain_height, this, _1), tr("Show blockchain height")); m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer, this, _1), tr("transfer [] [ ... ] [payment_id] - Transfer ,... to ,... , respectively. is the number of extra inputs to include for untraceability (from 0 to maximum available)")); m_cmd_binder.set_handler("transfer_new", boost::bind(&simple_wallet::transfer_new, this, _1), tr("Same as transfer, but using a new transaction building algorithm")); - m_cmd_binder.set_handler("sweep_dust", boost::bind(&simple_wallet::sweep_dust, this, _1), tr("Send all dust outputs to yourself with mixin 0")); + m_cmd_binder.set_handler("sweep_unmixable", boost::bind(&simple_wallet::sweep_unmixable, this, _1), tr("Send all unmixable outputs to yourself with mixin 0")); m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this, _1), tr("set_log - Change current log detail level, <0-4>")); m_cmd_binder.set_handler("address", boost::bind(&simple_wallet::print_address, this, _1), tr("Show current wallet public address")); m_cmd_binder.set_handler("integrated_address", boost::bind(&simple_wallet::print_integrated_address, this, _1), tr("integrated_address [PID] - Encode a payment ID into an integrated address for the current wallet public address (no argument uses a random payment ID), or decode an integrated address to standard address and payment ID")); @@ -1722,8 +1722,7 @@ bool simple_wallet::refresh(const std::vector& args) bool simple_wallet::show_balance(const std::vector& args/* = std::vector()*/) { success_msg_writer() << tr("Balance: ") << print_money(m_wallet->balance()) << ", " - << tr("unlocked balance: ") << print_money(m_wallet->unlocked_balance()) << ", " - << tr("including unlocked dust: ") << print_money(m_wallet->unlocked_dust_balance(tools::tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD))); + << tr("unlocked balance: ") << print_money(m_wallet->unlocked_balance()); return true; } //---------------------------------------------------------------------------------------------------- @@ -2208,7 +2207,7 @@ bool simple_wallet::transfer_new(const std::vector &args_) } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::sweep_dust(const std::vector &args_) +bool simple_wallet::sweep_unmixable(const std::vector &args_) { if (!try_connect_to_daemon()) return true; @@ -2221,28 +2220,37 @@ bool simple_wallet::sweep_dust(const std::vector &args_) try { - uint64_t total_dust = m_wallet->unlocked_dust_balance(tools::tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD)); - // figure out what tx will be necessary - auto ptx_vector = m_wallet->create_dust_sweep_transactions(); + auto ptx_vector = m_wallet->create_unmixable_sweep_transactions(); + + if (ptx_vector.empty()) + { + fail_msg_writer() << tr("No unmixable outputs found"); + return true; + } // give user total and fee, and prompt to confirm - uint64_t total_fee = 0; + uint64_t total_fee = 0, total_unmixable = 0; for (size_t n = 0; n < ptx_vector.size(); ++n) { total_fee += ptx_vector[n].fee; + for (const auto &vin: ptx_vector[n].tx.vin) + { + if (vin.type() == typeid(txin_to_key)) + total_unmixable += boost::get(vin).amount; + } } - std::string prompt_str = tr("Sweeping ") + print_money(total_dust); + std::string prompt_str = tr("Sweeping ") + print_money(total_unmixable); if (ptx_vector.size() > 1) { prompt_str = (boost::format(tr("Sweeping %s in %llu transactions for a total fee of %s. Is this okay? (Y/Yes/N/No)")) % - print_money(total_dust) % + print_money(total_unmixable) % ((unsigned long long)ptx_vector.size()) % print_money(total_fee)).str(); } else { prompt_str = (boost::format(tr("Sweeping %s for a total fee of %s. Is this okay? (Y/Yes/N/No)")) % - print_money(total_dust) % + print_money(total_unmixable) % print_money(total_fee)).str(); } std::string accepted = command_line::input_line(prompt_str); @@ -2285,11 +2293,12 @@ bool simple_wallet::sweep_dust(const std::vector &args_) } catch (const tools::error::not_enough_money& e) { - fail_msg_writer() << boost::format(tr("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)")) % + fail_msg_writer() << boost::format(tr("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee).\n%s")) % print_money(e.available()) % print_money(e.tx_amount() + e.fee()) % print_money(e.tx_amount()) % - print_money(e.fee()); + print_money(e.fee()) % + tr("This is usually due to dust which is so small it cannot pay for itself in fees"); } catch (const tools::error::not_enough_outs_to_mix& e) { diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 7dadb8536..21bbfa566 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -121,7 +121,7 @@ namespace cryptonote bool transfer_main(bool new_algorithm, const std::vector &args); bool transfer(const std::vector &args); bool transfer_new(const std::vector &args); - bool sweep_dust(const std::vector &args); + bool sweep_unmixable(const std::vector &args); std::vector> split_amounts( std::vector dsts, size_t num_splits ); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index aa638143c..7d308e615 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2508,7 +2508,7 @@ uint64_t wallet2::unlocked_dust_balance(const tx_dust_policy &dust_policy) const } template -void wallet2::transfer_dust(size_t num_outputs, uint64_t unlock_time, uint64_t needed_fee, T destination_split_strategy, const tx_dust_policy& dust_policy, const std::vector &extra, cryptonote::transaction& tx, pending_tx &ptx) +void wallet2::transfer_from(const std::vector &outs, size_t num_outputs, uint64_t unlock_time, uint64_t needed_fee, T destination_split_strategy, const tx_dust_policy& dust_policy, const std::vector &extra, cryptonote::transaction& tx, pending_tx &ptx) { using namespace cryptonote; @@ -2518,6 +2518,19 @@ void wallet2::transfer_dust(size_t num_outputs, uint64_t unlock_time, uint64_t n // throw if there are none uint64_t money = 0; std::list selected_transfers; +#if 1 + for (size_t n = 0; n < outs.size(); ++n) + { + const transfer_details& td = m_transfers[outs[n]]; + if (!td.m_spent) + { + selected_transfers.push_back (m_transfers.begin() + outs[n]); + money += td.amount(); + if (selected_transfers.size() >= num_outputs) + break; + } + } +#else for (transfer_container::iterator i = m_transfers.begin(); i != m_transfers.end(); ++i) { const transfer_details& td = *i; @@ -2529,6 +2542,7 @@ void wallet2::transfer_dust(size_t num_outputs, uint64_t unlock_time, uint64_t n break; } } +#endif // we don't allow no output to self, easier, but one may want to burn the dust if = fee THROW_WALLET_EXCEPTION_IF(money <= needed_fee, error::not_enough_money, money, needed_fee, needed_fee); @@ -2622,8 +2636,8 @@ bool wallet2::use_fork_rules(uint8_t version) r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/json_rpc", req_t, resp_t, m_http_client); m_daemon_rpc_mutex.unlock(); CHECK_AND_ASSERT_MES(r, false, "Failed to connect to daemon"); - CHECK_AND_ASSERT_MES(res.status != CORE_RPC_STATUS_BUSY, false, "Failed to connect to daemon"); - CHECK_AND_ASSERT_MES(res.status == CORE_RPC_STATUS_OK, false, "Failed to get hard fork status"); + CHECK_AND_ASSERT_MES(resp_t.result.status != CORE_RPC_STATUS_BUSY, false, "Failed to connect to daemon"); + CHECK_AND_ASSERT_MES(resp_t.result.status == CORE_RPC_STATUS_OK, false, "Failed to get hard fork status"); bool close_enough = res.height >= resp_t.result.earliest_height - 10; // start using the rules a bit beforehand if (close_enough) @@ -2641,20 +2655,84 @@ uint64_t wallet2::get_upper_tranaction_size_limit() return ((full_reward_zone * 125) / 100) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; } //---------------------------------------------------------------------------------------------------- -std::vector wallet2::create_dust_sweep_transactions() +std::vector wallet2::select_available_outputs(std::function f) +{ + std::vector outputs; + size_t n = 0; + for (transfer_container::const_iterator i = m_transfers.begin(); i != m_transfers.end(); ++i, ++n) + { + if (i->m_spent) + continue; + if (!is_transfer_unlocked(*i)) + continue; + if (f(*i)) + outputs.push_back(n); + } + return outputs; +} +//---------------------------------------------------------------------------------------------------- +std::vector wallet2::get_unspent_amounts_vector() +{ + std::set set; + for (const auto &td: m_transfers) + { + if (!td.m_spent) + set.insert(td.amount()); + } + std::vector vector; + vector.reserve(set.size()); + for (const auto &i: set) + { + vector.push_back(i); + } + return vector; +} +//---------------------------------------------------------------------------------------------------- +std::vector wallet2::select_available_unmixable_outputs() +{ + // request all outputs with at least 3 instances, so we can use mixin 2 with + epee::json_rpc::request req_t = AUTO_VAL_INIT(req_t); + epee::json_rpc::response resp_t = AUTO_VAL_INIT(resp_t); + m_daemon_rpc_mutex.lock(); + req_t.jsonrpc = "2.0"; + req_t.id = epee::serialization::storage_entry(0); + req_t.method = "get_output_histogram"; + req_t.params.amounts = get_unspent_amounts_vector(); + req_t.params.min_count = 3; + 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); + 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"); + THROW_WALLET_EXCEPTION_IF(resp_t.result.status != CORE_RPC_STATUS_OK, error::get_histogram_error, resp_t.result.status); + + std::set mixable; + for (const auto &i: resp_t.result.histogram) + { + mixable.insert(i.amount); + } + + return select_available_outputs([mixable](const transfer_details &td) { + const uint64_t amount = td.amount(); + if (mixable.find(amount) == mixable.end()) + return true; + return false; + }); +} +//---------------------------------------------------------------------------------------------------- +std::vector wallet2::create_unmixable_sweep_transactions() { // From hard fork 1, we don't consider small amounts to be dust anymore const bool hf1_rules = use_fork_rules(2); // first hard fork has version 2 tx_dust_policy dust_policy(hf1_rules ? 0 : ::config::DEFAULT_DUST_THRESHOLD); - size_t num_dust_outputs = 0; - for (transfer_container::const_iterator i = m_transfers.begin(); i != m_transfers.end(); ++i) + // may throw + std::vector unmixable_outputs = select_available_unmixable_outputs(); + size_t num_dust_outputs = unmixable_outputs.size(); + + if (num_dust_outputs == 0) { - const transfer_details& td = *i; - if (!td.m_spent && (td.amount() < dust_policy.dust_threshold || !is_valid_decomposed_amount(td.amount())) && is_transfer_unlocked(td)) - { - num_dust_outputs++; - } + return std::vector(); } // failsafe split attempt counter @@ -2679,13 +2757,13 @@ std::vector wallet2::create_dust_sweep_transactions() uint64_t needed_fee = 0; do { - transfer_dust(num_outputs_per_tx, (uint64_t)0 /* unlock_time */, 0, detail::digit_split_strategy, dust_policy, extra, tx, ptx); + transfer_from(unmixable_outputs, num_outputs_per_tx, (uint64_t)0 /* unlock_time */, 0, detail::digit_split_strategy, dust_policy, extra, tx, ptx); auto txBlob = t_serializable_object_to_blob(ptx.tx); needed_fee = calculate_fee(txBlob); // reroll the tx with the actual amount minus the fee // if there's not enough for the fee, it'll throw - transfer_dust(num_outputs_per_tx, (uint64_t)0 /* unlock_time */, needed_fee, detail::digit_split_strategy, dust_policy, extra, tx, ptx); + transfer_from(unmixable_outputs, num_outputs_per_tx, (uint64_t)0 /* unlock_time */, needed_fee, detail::digit_split_strategy, dust_policy, extra, tx, ptx); txBlob = t_serializable_object_to_blob(ptx.tx); needed_fee = calculate_fee(txBlob); } while (ptx.fee < needed_fee); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index e7b002925..2b6cdab92 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -280,7 +280,7 @@ namespace tools void transfer(const std::vector& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector& extra); void transfer(const std::vector& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector& extra, cryptonote::transaction& tx, pending_tx& ptx); template - void transfer_dust(size_t num_outputs, uint64_t unlock_time, uint64_t needed_fee, T destination_split_strategy, const tx_dust_policy& dust_policy, const std::vector& extra, cryptonote::transaction& tx, pending_tx &ptx); + void transfer_from(const std::vector &outs, size_t num_outputs, uint64_t unlock_time, uint64_t needed_fee, T destination_split_strategy, const tx_dust_policy& dust_policy, const std::vector& extra, cryptonote::transaction& tx, pending_tx &ptx); template void transfer_selected(const std::vector& dsts, const std::list selected_transfers, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx); @@ -289,7 +289,7 @@ namespace tools void commit_tx(std::vector& ptx_vector); std::vector create_transactions(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee, const std::vector extra); std::vector create_transactions_2(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector extra); - std::vector create_dust_sweep_transactions(); + std::vector create_unmixable_sweep_transactions(); bool check_connection(); void get_transfers(wallet2::transfer_container& incoming_transfers) const; void get_payments(const crypto::hash& payment_id, std::list& payments, uint64_t min_height = 0) const; @@ -402,6 +402,9 @@ namespace tools void parse_block_round(const cryptonote::blobdata &blob, cryptonote::block &bl, crypto::hash &bl_id, bool &error) const; uint64_t get_upper_tranaction_size_limit(); void check_pending_txes(); + std::vector get_unspent_amounts_vector(); + std::vector select_available_outputs(std::function f); + std::vector select_available_unmixable_outputs(); cryptonote::account_base m_account; std::string m_daemon_address; diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h index 6074e0858..652b19499 100644 --- a/src/wallet/wallet_errors.h +++ b/src/wallet/wallet_errors.h @@ -76,6 +76,7 @@ namespace tools // daemon_busy // no_connection_to_daemon // is_key_image_spent_error + // get_histogram_error // wallet_files_doesnt_correspond // // * - class with protected ctor @@ -600,6 +601,14 @@ namespace tools } }; //---------------------------------------------------------------------------------------------------- + struct get_histogram_error : public wallet_rpc_error + { + explicit get_histogram_error(std::string&& loc, const std::string& request) + : wallet_rpc_error(std::move(loc), "failed to get output histogram", request) + { + } + }; + //---------------------------------------------------------------------------------------------------- struct wallet_files_doesnt_correspond : public wallet_logic_error { explicit wallet_files_doesnt_correspond(std::string&& loc, const std::string& keys_file, const std::string& wallet_file) diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 418de327c..83e1f7535 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -347,7 +347,7 @@ namespace tools try { - std::vector ptx_vector = m_wallet.create_dust_sweep_transactions(); + std::vector ptx_vector = m_wallet.create_unmixable_sweep_transactions(); m_wallet.commit_tx(ptx_vector); -- cgit v1.2.3 From 0be6e08dd0faf5f7e3492652f00b8904e7e8216d Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 26 Mar 2016 23:22:57 +0000 Subject: wallet: do not leak owned amounts to the daemon unless --trusted-daemon This will be slower, though more private. New trusted_daemon parameter to the matching RPC call, false by default. --- src/simplewallet/simplewallet.cpp | 2 +- src/wallet/wallet2.cpp | 9 +++++---- src/wallet/wallet2.h | 4 ++-- src/wallet/wallet_rpc_server.cpp | 2 +- src/wallet/wallet_rpc_server_commands_defs.h | 2 ++ 5 files changed, 11 insertions(+), 8 deletions(-) (limited to 'src/wallet/wallet2.cpp') diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index dd166ede5..04170df62 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -2221,7 +2221,7 @@ bool simple_wallet::sweep_unmixable(const std::vector &args_) try { // figure out what tx will be necessary - auto ptx_vector = m_wallet->create_unmixable_sweep_transactions(); + auto ptx_vector = m_wallet->create_unmixable_sweep_transactions(m_trusted_daemon); if (ptx_vector.empty()) { diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 7d308e615..3ec2265fa 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2688,7 +2688,7 @@ std::vector wallet2::get_unspent_amounts_vector() return vector; } //---------------------------------------------------------------------------------------------------- -std::vector wallet2::select_available_unmixable_outputs() +std::vector wallet2::select_available_unmixable_outputs(bool trusted_daemon) { // request all outputs with at least 3 instances, so we can use mixin 2 with epee::json_rpc::request req_t = AUTO_VAL_INIT(req_t); @@ -2697,7 +2697,8 @@ std::vector wallet2::select_available_unmixable_outputs() req_t.jsonrpc = "2.0"; req_t.id = epee::serialization::storage_entry(0); req_t.method = "get_output_histogram"; - req_t.params.amounts = get_unspent_amounts_vector(); + if (trusted_daemon) + req_t.params.amounts = get_unspent_amounts_vector(); req_t.params.min_count = 3; 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); @@ -2720,14 +2721,14 @@ std::vector wallet2::select_available_unmixable_outputs() }); } //---------------------------------------------------------------------------------------------------- -std::vector wallet2::create_unmixable_sweep_transactions() +std::vector wallet2::create_unmixable_sweep_transactions(bool trusted_daemon) { // From hard fork 1, we don't consider small amounts to be dust anymore const bool hf1_rules = use_fork_rules(2); // first hard fork has version 2 tx_dust_policy dust_policy(hf1_rules ? 0 : ::config::DEFAULT_DUST_THRESHOLD); // may throw - std::vector unmixable_outputs = select_available_unmixable_outputs(); + std::vector unmixable_outputs = select_available_unmixable_outputs(trusted_daemon); size_t num_dust_outputs = unmixable_outputs.size(); if (num_dust_outputs == 0) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 2b6cdab92..566be59c6 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -289,7 +289,7 @@ namespace tools void commit_tx(std::vector& ptx_vector); std::vector create_transactions(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee, const std::vector extra); std::vector create_transactions_2(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector extra); - std::vector create_unmixable_sweep_transactions(); + std::vector create_unmixable_sweep_transactions(bool trusted_daemon); bool check_connection(); void get_transfers(wallet2::transfer_container& incoming_transfers) const; void get_payments(const crypto::hash& payment_id, std::list& payments, uint64_t min_height = 0) const; @@ -404,7 +404,7 @@ namespace tools void check_pending_txes(); std::vector get_unspent_amounts_vector(); std::vector select_available_outputs(std::function f); - std::vector select_available_unmixable_outputs(); + std::vector select_available_unmixable_outputs(bool trusted_daemon); cryptonote::account_base m_account; std::string m_daemon_address; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 83e1f7535..d7d99c2ae 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -347,7 +347,7 @@ namespace tools try { - std::vector ptx_vector = m_wallet.create_unmixable_sweep_transactions(); + std::vector ptx_vector = m_wallet.create_unmixable_sweep_transactions(req.trusted_daemon); m_wallet.commit_tx(ptx_vector); diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index 40d6fd8f8..2c4e26406 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -178,9 +178,11 @@ namespace wallet_rpc struct request { bool get_tx_keys; + bool trusted_daemon; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(get_tx_keys) + KV_SERIALIZE(trusted_daemon) END_KV_SERIALIZE_MAP() }; -- cgit v1.2.3 From 25672d3f10e71f4db36d9497e2440f2ac26a6e01 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 26 Mar 2016 23:32:45 +0000 Subject: wallet: pass std::function by const ref, not value Because we can. --- src/wallet/wallet2.cpp | 2 +- src/wallet/wallet2.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/wallet/wallet2.cpp') diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 3ec2265fa..6fd77eead 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2655,7 +2655,7 @@ uint64_t wallet2::get_upper_tranaction_size_limit() return ((full_reward_zone * 125) / 100) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; } //---------------------------------------------------------------------------------------------------- -std::vector wallet2::select_available_outputs(std::function f) +std::vector wallet2::select_available_outputs(const std::function &f) { std::vector outputs; size_t n = 0; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 566be59c6..fc700a3de 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -403,7 +403,7 @@ namespace tools uint64_t get_upper_tranaction_size_limit(); void check_pending_txes(); std::vector get_unspent_amounts_vector(); - std::vector select_available_outputs(std::function f); + std::vector select_available_outputs(const std::function &f); std::vector select_available_unmixable_outputs(bool trusted_daemon); cryptonote::account_base m_account; -- cgit v1.2.3 From 878ab5d896c1a9cb5c50c36a0ded5da998c941d5 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Mon, 28 Mar 2016 16:46:19 +0100 Subject: wallet: fix --generate-from-keys saving as watch only --- src/wallet/wallet2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/wallet/wallet2.cpp') diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 6fd77eead..363665024 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1214,7 +1214,7 @@ void wallet2::generate(const std::string& wallet_, const std::string& password, m_account_public_address = account_public_address; m_watch_only = false; - bool r = store_keys(m_keys_file, password, true); + bool r = store_keys(m_keys_file, password, false); THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file); r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_testnet)); -- cgit v1.2.3