diff options
32 files changed, 466 insertions, 75 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index c375defe6..084c087d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -243,6 +243,15 @@ 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") + set(LIBUNWIND_LIBRARIES "") +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) @@ -274,6 +283,10 @@ 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") @@ -310,7 +323,7 @@ else() endif() if(MINGW) set(WARNINGS "${WARNINGS} -Wno-error=unused-value -Wno-error=unused-but-set-variable") - set(MINGW_FLAG "${MINGW_FLAG} -DWIN32_LEAN_AND_MEAN") + set(MINGW_FLAG "${MINGW_FLAG} -DWIN32_LEAN_AND_MEAN -D_POSIX_C_SOURCE") set(Boost_THREADAPI win32) include_directories(SYSTEM src/platform/mingw) # mingw doesn't support LTO (multiple definition errors at link time) @@ -394,6 +407,7 @@ else() set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${RELEASE_FLAGS}") if(STATIC AND NOT APPLE AND NOT FREEBSD AND NOT OPENBSD) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--wrap=__cxa_throw") endif() endif() @@ -431,6 +445,11 @@ elseif(NOT MSVC) set(EXTRA_LIBRARIES ${RT}) endif() +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT MINGW) + find_library(DL dl) + set(EXTRA_LIBRARIES ${DL}) +endif() + include(version.cmake) add_subdirectory(contrib) @@ -187,6 +187,24 @@ Dependencies: Doxygen 1.8.0 or later, Graphviz 2.28 or later (optional). * If you have installed Graphviz, you can also generate in-doc diagrams by instead running `HAVE_DOT=YES doxygen Doxyfile` * The output will be built in doc/html/ +## Running bitmonerod + +The build places the binary in `bin/` sub-directory within the build directory +from which cmake was invoked (repository root by default). To run in +foreground: + + ./bin/bitmonerod + +To run in background: + + ./bin/bitmonerod --log-file bitmonerod.log --detach + +To list all available options, run `./bin/bitmonerod --help`. Options can be +specified either on the command line or in a configuration file passed by the +`--config-file` argument. To specify an option in the configuration file, add +a line with the syntax `argumentname=value`, where `argumentname` is the name +of the argument without any dashes, for example `log-level=1`. + ## Internationalization See README.i18n diff --git a/cmake/FindLibunwind.cmake b/cmake/FindLibunwind.cmake new file mode 100644 index 000000000..9946e7cdd --- /dev/null +++ b/cmake/FindLibunwind.cmake @@ -0,0 +1,25 @@ +# - 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, <adymo@kdevelop.org> +# +# 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/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl index ca9429c91..94dbe7458 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -88,7 +88,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) PRAGMA_WARNING_DISABLE_VS(4355) //--------------------------------------------------------------------------------- template<class t_protocol_handler> - connection<t_protocol_handler>::~connection() + connection<t_protocol_handler>::~connection() noexcept(false) { if(!m_was_shutdown) { diff --git a/contrib/epee/include/net/net_utils_base.h b/contrib/epee/include/net/net_utils_base.h index f963e7746..78e555fac 100644 --- a/contrib/epee/include/net/net_utils_base.h +++ b/contrib/epee/include/net/net_utils_base.h @@ -119,7 +119,7 @@ namespace net_utils virtual bool add_ref()=0; virtual bool release()=0; protected: - virtual ~i_service_endpoint(){} + virtual ~i_service_endpoint() noexcept(false) {} }; diff --git a/contrib/epee/include/storages/portable_storage_from_bin.h b/contrib/epee/include/storages/portable_storage_from_bin.h index bc2fb1463..44a80cb21 100644 --- a/contrib/epee/include/storages/portable_storage_from_bin.h +++ b/contrib/epee/include/storages/portable_storage_from_bin.h @@ -68,7 +68,7 @@ namespace epee ++m_counter_ref; CHECK_AND_ASSERT_THROW_MES(m_counter_ref < EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL, "Wrong blob data in portable storage: recursion limitation (" << EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL << ") exceeded"); } - ~recursuion_limitation_guard() + ~recursuion_limitation_guard() noexcept(false) { CHECK_AND_ASSERT_THROW_MES(m_counter_ref != 0, "Internal error: m_counter_ref == 0 while ~recursuion_limitation_guard()"); --m_counter_ref; diff --git a/contrib/epee/include/string_tools.h b/contrib/epee/include/string_tools.h index 8289ee0ba..b973c6d48 100644 --- a/contrib/epee/include/string_tools.h +++ b/contrib/epee/include/string_tools.h @@ -139,9 +139,11 @@ namespace string_tools } //---------------------------------------------------------------------------- template<class CharT> - bool parse_hexstr_to_binbuff(const std::basic_string<CharT>& s, std::basic_string<CharT>& res) + bool parse_hexstr_to_binbuff(const std::basic_string<CharT>& s, std::basic_string<CharT>& res, bool allow_partial_byte = false) { res.clear(); + if (!allow_partial_byte && (s.size() & 1)) + return false; try { long v = 0; diff --git a/external/db_drivers/liblmdb/midl.h b/external/db_drivers/liblmdb/midl.h index e16aa0c3c..1555ecb19 100644 --- a/external/db_drivers/liblmdb/midl.h +++ b/external/db_drivers/liblmdb/midl.h @@ -60,11 +60,7 @@ typedef MDB_ID *MDB_IDL; /* IDL sizes - likely should be even bigger * limiting factors: sizeof(ID), thread stack size */ -#ifdef MDB_VL32 -#define MDB_IDL_LOGN 14 /* DB_SIZE is 2^14, UM_SIZE is 2^15 */ -#else #define MDB_IDL_LOGN 16 /* DB_SIZE is 2^16, UM_SIZE is 2^17 */ -#endif #define MDB_IDL_DB_SIZE (1<<MDB_IDL_LOGN) #define MDB_IDL_UM_SIZE (1<<(MDB_IDL_LOGN+1)) diff --git a/src/blockchain_utilities/cn_deserialize.cpp b/src/blockchain_utilities/cn_deserialize.cpp index b8d38c9af..a8448dcee 100644 --- a/src/blockchain_utilities/cn_deserialize.cpp +++ b/src/blockchain_utilities/cn_deserialize.cpp @@ -160,8 +160,9 @@ int main(int argc, char* argv[]) std::cout << "field " << n << ": "; if (typeid(cryptonote::tx_extra_padding) == fields[n].type()) std::cout << "extra padding: " << boost::get<cryptonote::tx_extra_padding>(fields[n]).size << " bytes"; else if (typeid(cryptonote::tx_extra_pub_key) == fields[n].type()) std::cout << "extra pub key: " << boost::get<cryptonote::tx_extra_pub_key>(fields[n]).pub_key; - else if (typeid(cryptonote::tx_extra_nonce) == fields[n].type()) std::cout << "extra nonce: " << boost::get<cryptonote::tx_extra_nonce>(fields[n]).nonce; + else if (typeid(cryptonote::tx_extra_nonce) == fields[n].type()) std::cout << "extra nonce: " << epee::string_tools::buff_to_hex_nodelimer(boost::get<cryptonote::tx_extra_nonce>(fields[n]).nonce); else if (typeid(cryptonote::tx_extra_merge_mining_tag) == fields[n].type()) std::cout << "extra merge mining tag: depth " << boost::get<cryptonote::tx_extra_merge_mining_tag>(fields[n]).depth << ", merkle root " << boost::get<cryptonote::tx_extra_merge_mining_tag>(fields[n]).merkle_root; + else if (typeid(cryptonote::tx_extra_mysterious_minergate) == fields[n].type()) std::cout << "extra minergate custom: " << epee::string_tools::buff_to_hex_nodelimer(boost::get<cryptonote::tx_extra_mysterious_minergate>(fields[n]).data); else std::cout << "unknown"; std::cout << std::endl; } diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 2289704e5..9afbe4b82 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -31,7 +31,8 @@ set(common_sources command_line.cpp dns_utils.cpp util.cpp - i18n.cpp) + i18n.cpp + stack_trace.cpp) set(common_headers) @@ -48,7 +49,8 @@ set(common_private_headers unordered_containers_boost_serialization.h util.h varint.h - i18n.h) + i18n.h + stack_trace.h) bitmonero_private_headers(common ${common_private_headers}) @@ -60,6 +62,7 @@ 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/stack_trace.cpp b/src/common/stack_trace.cpp new file mode 100644 index 000000000..2805e7604 --- /dev/null +++ b/src/common/stack_trace.cpp @@ -0,0 +1,120 @@ +// 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/stack_trace.h" +#include "misc_log_ex.h" +#ifdef HAVE_LIBUNWIND +#define UNW_LOCAL_ONLY +#include <libunwind.h> +#endif +#include <cxxabi.h> +#include <dlfcn.h> + +// from http://stackoverflow.com/questions/11665829/how-can-i-print-stack-trace-for-caught-exceptions-in-c-code-injection-in-c +#ifdef STATICLIB +#define CXA_THROW __wrap___cxa_throw +extern "C" void __real___cxa_throw(void *ex, void *info, void (*dest)(void*)); +#else +#define CXA_THROW __cxa_throw +#endif + +extern "C" void CXA_THROW(void *ex, void *info, void (*dest)(void*)) +{ + + int status; + char *dsym = abi::__cxa_demangle(((const std::type_info*)info)->name(), NULL, NULL, &status); + tools::log_stack_trace((std::string("Exception: ")+((!status && dsym) ? dsym : (const char*)info)).c_str()); + free(dsym); + +#ifdef STATICLIB + __real___cxa_throw(ex, info, dest); +#else + static void (*const rethrow)(void*, void*, void(*)(void*)) __attribute__((noreturn)) = (void(*)(void*, void*, void(*)(void*)))dlsym(RTLD_NEXT, "__cxa_throw"); + rethrow(ex, info, dest); +#endif +} + +namespace +{ + std::string stack_trace_log; +} + +namespace tools +{ + +void set_stack_trace_log(const std::string &log) +{ + stack_trace_log = log; +} + +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; + const char *log = stack_trace_log.empty() ? NULL : stack_trace_log.c_str(); + + if (msg) + LOG_PRINT2(log, msg, LOG_LEVEL_0); + LOG_PRINT2(log, "Unwinded call stack:", LOG_LEVEL_0); + if (unw_getcontext(&ctx) < 0) { + LOG_PRINT2(log, "Failed to create unwind context", LOG_LEVEL_0); + return; + } + if (unw_init_local(&cur, &ctx) < 0) { + LOG_PRINT2(log, "Failed to find the first unwind frame", LOG_LEVEL_0); + return; + } + for (level = 1; level < 999; ++level) { // 999 for safety + int ret = unw_step(&cur); + if (ret < 0) { + LOG_PRINT2(log, "Failed to find the next frame", LOG_LEVEL_0); + return; + } + if (ret == 0) + break; + if (unw_get_reg(&cur, UNW_REG_IP, &ip) < 0) { + LOG_PRINT2(log, " " << std::setw(4) << level, LOG_LEVEL_0); + continue; + } + if (unw_get_proc_name(&cur, sym, sizeof(sym), &off) < 0) { + LOG_PRINT2(log, " " << std::setw(4) << level << std::setbase(16) << std::setw(20) << "0x" << ip, LOG_LEVEL_0); + continue; + } + dsym = abi::__cxa_demangle(sym, NULL, NULL, &status); + LOG_PRINT2(log, " " << std::setw(4) << level << std::setbase(16) << std::setw(20) << "0x" << ip << " " << (!status && dsym ? dsym : sym) << " + " << "0x" << off, LOG_LEVEL_0); + free(dsym); + } +#endif +} + +} // namespace tools diff --git a/src/common/stack_trace.h b/src/common/stack_trace.h new file mode 100644 index 000000000..25eec9fb3 --- /dev/null +++ b/src/common/stack_trace.h @@ -0,0 +1,43 @@ +// 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 <stdexcept> +#include <string> + +namespace tools +{ + +void set_stack_trace_log(const std::string &log); +void log_stack_trace(const char *msg); + +} // namespace tools + +#endif diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp index e251d0ec2..f5e655274 100644 --- a/src/crypto/crypto.cpp +++ b/src/crypto/crypto.cpp @@ -263,16 +263,17 @@ namespace crypto { PUSH_WARNINGS DISABLE_VS_WARNINGS(4200) + struct ec_point_pair { + ec_point a, b; + }; struct rs_comm { hash h; - struct { - ec_point a, b; - } ab[]; + struct ec_point_pair ab[]; }; POP_WARNINGS static inline size_t rs_comm_size(size_t pubs_count) { - return sizeof(rs_comm) + pubs_count * sizeof(rs_comm().ab[0]); + return sizeof(rs_comm) + pubs_count * sizeof(ec_point_pair); } void crypto_ops::generate_ring_signature(const hash &prefix_hash, const key_image &image, diff --git a/src/crypto/oaes_lib.c b/src/crypto/oaes_lib.c index 7fbe96e4c..4c1446898 100644 --- a/src/crypto/oaes_lib.c +++ b/src/crypto/oaes_lib.c @@ -27,10 +27,6 @@ * POSSIBILITY OF SUCH DAMAGE. * --------------------------------------------------------------------------- */ -static const char _NR[] = { - 0x4e,0x61,0x62,0x69,0x6c,0x20,0x53,0x2e,0x20, - 0x41,0x6c,0x20,0x52,0x61,0x6d,0x6c,0x69,0x00 }; - #include <stddef.h> #include <time.h> #include <string.h> diff --git a/src/crypto/slow-hash.c b/src/crypto/slow-hash.c index 4efa8af6c..8a1807657 100644 --- a/src/crypto/slow-hash.c +++ b/src/crypto/slow-hash.c @@ -658,10 +658,6 @@ void slow_hash_free_state(void) return; } -static void (*const extra_hashes[4])(const void *, size_t, char *) = { - hash_extra_blake, hash_extra_groestl, hash_extra_jh, hash_extra_skein -}; - #define MEMORY (1 << 21) /* 2 MiB */ #define ITER (1 << 20) #define AES_BLOCK_SIZE 16 @@ -683,7 +679,8 @@ static void (*const extra_hashes[4])(const void *, size_t, char *) = { #include "aesb.c" -/* The asm corresponds to this C code +#ifndef ARM_MUL_IMPL_ASM +/* The asm corresponds to this C code */ #define SHORT uint32_t #define LONG uint64_t @@ -714,7 +711,8 @@ void mul(const uint8_t *ca, const uint8_t *cb, uint8_t *cres) { res[3] = t.tmp[2]; res[0] = t.tmp[6]; res[1] = t.tmp[7]; -} */ +} +#else // ARM_MUL_IMPL_ASM (TODO: this fails hash-slow test with GCC 6.1.1) /* Can work as inline, but actually runs slower. Keep it separate */ #define mul(a, b, c) cn_mul128(a, b, c) @@ -749,6 +747,7 @@ __asm__ __volatile__( : [A]"r"(aa[1]), [a]"r"(aa[0]), [B]"r"(bb[1]), [b]"r"(bb[0]), [r]"r"(r) : "cc", "memory"); } +#endif // ARM_MUL_IMPL_ASM STATIC INLINE void sum_half_blocks(uint8_t* a, const uint8_t* b) { @@ -824,7 +823,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash) { for(j = 0; j < INIT_SIZE_BLK; j++) aesb_pseudo_round(&text[AES_BLOCK_SIZE * j], &text[AES_BLOCK_SIZE * j], expandedKey); - memcpy(&long_state[i * INIT_SIZE_BYTE], text, INIT_SIZE_BYTE); + memcpy(&long_state[i * INIT_SIZE_BYTE], text, INIT_SIZE_BYTE); } U64(a)[0] = U64(&state.k[0])[0] ^ U64(&state.k[32])[0]; diff --git a/src/cryptonote_core/tx_extra.h b/src/cryptonote_core/tx_extra.h index 93d2e21b3..6f5fbe466 100644 --- a/src/cryptonote_core/tx_extra.h +++ b/src/cryptonote_core/tx_extra.h @@ -38,6 +38,7 @@ #define TX_EXTRA_TAG_PUBKEY 0x01 #define TX_EXTRA_NONCE 0x02 #define TX_EXTRA_MERGE_MINING_TAG 0x03 +#define TX_EXTRA_MYSTERIOUS_MINERGATE_TAG 0xDE #define TX_EXTRA_NONCE_PAYMENT_ID 0x00 #define TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID 0x01 @@ -158,14 +159,24 @@ namespace cryptonote } }; + struct tx_extra_mysterious_minergate + { + std::string data; + + BEGIN_SERIALIZE() + FIELD(data) + END_SERIALIZE() + }; + // tx_extra_field format, except tx_extra_padding and tx_extra_pub_key: // varint tag; // varint size; // varint data[]; - typedef boost::variant<tx_extra_padding, tx_extra_pub_key, tx_extra_nonce, tx_extra_merge_mining_tag> tx_extra_field; + typedef boost::variant<tx_extra_padding, tx_extra_pub_key, tx_extra_nonce, tx_extra_merge_mining_tag, tx_extra_mysterious_minergate> tx_extra_field; } VARIANT_TAG(binary_archive, cryptonote::tx_extra_padding, TX_EXTRA_TAG_PADDING); VARIANT_TAG(binary_archive, cryptonote::tx_extra_pub_key, TX_EXTRA_TAG_PUBKEY); VARIANT_TAG(binary_archive, cryptonote::tx_extra_nonce, TX_EXTRA_NONCE); VARIANT_TAG(binary_archive, cryptonote::tx_extra_merge_mining_tag, TX_EXTRA_MERGE_MINING_TAG); +VARIANT_TAG(binary_archive, cryptonote::tx_extra_mysterious_minergate, TX_EXTRA_MYSTERIOUS_MINERGATE_TAG); diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp index bfd829dea..2e2f8936c 100644 --- a/src/daemon/main.cpp +++ b/src/daemon/main.cpp @@ -31,6 +31,7 @@ #include "common/command_line.h" #include "common/scoped_message_writer.h" #include "common/util.h" +#include "common/stack_trace.h" #include "cryptonote_core/cryptonote_core.h" #include "cryptonote_core/miner.h" #include "daemon/command_server.h" @@ -259,6 +260,7 @@ int main(int argc, char const * argv[]) , log_file_path.filename().string().c_str() , log_file_path.parent_path().string().c_str() ); + tools::set_stack_trace_log(log_file_path.filename().string()); } if (command_line::has_arg(vm, daemon_args::arg_max_concurrency)) diff --git a/src/p2p/connection_basic.cpp b/src/p2p/connection_basic.cpp index c0b73bc3e..981a02882 100644 --- a/src/p2p/connection_basic.cpp +++ b/src/p2p/connection_basic.cpp @@ -161,16 +161,16 @@ connection_basic::connection_basic(boost::asio::io_service& io_service, std::ato mI->m_peer_number = sock_number.fetch_add(1); // use, and increase the generated number string remote_addr_str = "?"; - try { remote_addr_str = socket_.remote_endpoint().address().to_string(); } catch(...){} ; + try { boost::system::error_code e; remote_addr_str = socket_.remote_endpoint(e).address().to_string(); } catch(...){} ; _note("Spawned connection p2p#"<<mI->m_peer_number<<" to " << remote_addr_str << " currently we have sockets count:" << m_ref_sock_count); //boost::filesystem::create_directories("log/dr-monero/net/"); } -connection_basic::~connection_basic() { +connection_basic::~connection_basic() noexcept(false) { string remote_addr_str = "?"; m_ref_sock_count--; - try { remote_addr_str = socket_.remote_endpoint().address().to_string(); } catch(...){} ; + try { boost::system::error_code e; remote_addr_str = socket_.remote_endpoint(e).address().to_string(); } catch(...){} ; _note("Destructing connection p2p#"<<mI->m_peer_number << " to " << remote_addr_str); } diff --git a/src/p2p/connection_basic.hpp b/src/p2p/connection_basic.hpp index 8be798735..5452fa6fb 100644 --- a/src/p2p/connection_basic.hpp +++ b/src/p2p/connection_basic.hpp @@ -103,7 +103,7 @@ class connection_basic { // not-templated base class for rapid developmet of som // first counter is the ++/-- count of current sockets, the other socket_number is only-increasing ++ number generator connection_basic(boost::asio::io_service& io_service, std::atomic<long> &ref_sock_count, std::atomic<long> &sock_number); - virtual ~connection_basic(); + virtual ~connection_basic() noexcept(false); // various handlers to be called from connection class: void do_send_handler_write(const void * ptr , size_t cb); diff --git a/src/p2p/data_logger.cpp b/src/p2p/data_logger.cpp index ca0726c5f..fe54aef63 100644 --- a/src/p2p/data_logger.cpp +++ b/src/p2p/data_logger.cpp @@ -103,7 +103,7 @@ namespace net_utils _info_c("dbg/data","Data logger constructed"); } - data_logger::~data_logger() { + data_logger::~data_logger() noexcept(false) { _note_c("dbg/data","Destructor of the data logger"); { boost::lock_guard<boost::mutex> lock(mMutex); diff --git a/src/p2p/data_logger.hpp b/src/p2p/data_logger.hpp index 148afc0ab..278d08bfc 100644 --- a/src/p2p/data_logger.hpp +++ b/src/p2p/data_logger.hpp @@ -55,7 +55,7 @@ enum class data_logger_state { state_before_init, state_during_init, state_ready public: static data_logger &get_instance(); ///< singleton static void kill_instance(); ///< call this before ending main to allow more gracefull shutdown of the main singleton and it's background thread - ~data_logger(); ///< destr, will be called when singleton is killed when global m_obj dies. will kill theads etc + ~data_logger() noexcept(false); ///< destr, will be called when singleton is killed when global m_obj dies. will kill theads etc private: data_logger(); ///< constructor is private, use only via singleton get_instance diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 9e8d1108e..cfe1057ac 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -930,7 +930,7 @@ namespace cryptonote { res.tx_hashes.push_back(epee::string_tools::pod_to_hex(blk.tx_hashes[n])); } - res.blob = t_serializable_object_to_blob(blk); + res.blob = string_tools::buff_to_hex_nodelimer(t_serializable_object_to_blob(blk)); res.json = obj_to_json_str(blk); res.status = CORE_RPC_STATUS_OK; return true; diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 7d28de9c0..0581d9de9 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -595,6 +595,7 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("rescan_bc", boost::bind(&simple_wallet::rescan_blockchain, this, _1), tr("Rescan blockchain from scratch")); m_cmd_binder.set_handler("set_tx_note", boost::bind(&simple_wallet::set_tx_note, this, _1), tr("Set an arbitrary string note for a txid")); m_cmd_binder.set_handler("get_tx_note", boost::bind(&simple_wallet::get_tx_note, this, _1), tr("Get a string note for a txid")); + m_cmd_binder.set_handler("status", boost::bind(&simple_wallet::status, this, _1), tr("Show wallet status information")); m_cmd_binder.set_handler("help", boost::bind(&simple_wallet::help, this, _1), tr("Show this help")); } //---------------------------------------------------------------------------------------------------- @@ -2968,13 +2969,17 @@ static std::string get_human_readable_timestamp(uint64_t ts) return "<unknown>"; time_t tt = ts; struct tm tm; +#ifdef WIN32 + gmtime_s(&tm, &tt); +#else gmtime_r(&tt, &tm); +#endif uint64_t now = time(NULL); uint64_t diff = ts > now ? ts - now : now - ts; if (diff > 24*3600) - strftime(buffer, sizeof(buffer), "%F", &tm); + strftime(buffer, sizeof(buffer), "%Y-%m-%d", &tm); else - strftime(buffer, sizeof(buffer), "%r", &tm); + strftime(buffer, sizeof(buffer), "%I:%M:%S %p", &tm); return std::string(buffer); } //---------------------------------------------------------------------------------------------------- @@ -2994,7 +2999,7 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_) } LOCK_REFRESH_THREAD_SCOPE(); - + // optional in/out selector if (local_args.size() > 0) { if (local_args[0] == "in" || local_args[0] == "incoming") { @@ -3261,6 +3266,29 @@ bool simple_wallet::get_tx_note(const std::vector<std::string> &args) return true; } //---------------------------------------------------------------------------------------------------- +bool simple_wallet::status(const std::vector<std::string> &args) +{ + uint64_t local_height = m_wallet->get_blockchain_current_height(); + if (!m_wallet->check_connection()) + { + success_msg_writer() << "Refreshed " << local_height << "/?, no daemon connected"; + return true; + } + + std::string err; + uint64_t bc_height = get_daemon_blockchain_height(err); + if (err.empty()) + { + bool synced = local_height == bc_height; + success_msg_writer() << "Refreshed " << local_height << "/" << bc_height << ", " << (synced ? "synced" : "syncing"); + } + else + { + fail_msg_writer() << "Refreshed " << local_height << "/?, daemon connection error"; + } + return true; +} +//---------------------------------------------------------------------------------------------------- bool simple_wallet::process_command(const std::vector<std::string> &args) { return m_cmd_binder.process_command_vec(args); diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 0c69f0440..66f74b456 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -141,6 +141,7 @@ namespace cryptonote bool refresh_main(uint64_t start_height, bool reset = false); bool set_tx_note(const std::vector<std::string> &args); bool get_tx_note(const std::vector<std::string> &args); + bool status(const std::vector<std::string> &args); uint64_t get_daemon_blockchain_height(std::string& err); bool try_connect_to_daemon(); diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index d72ebc8da..be379cb99 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -137,6 +137,12 @@ uint64_t Wallet::amountFromDouble(double amount) return amountFromString(ss.str()); } +std::string Wallet::genPaymentId() +{ + crypto::hash8 payment_id = crypto::rand<crypto::hash8>(); + return epee::string_tools::pod_to_hex(payment_id); + +} ///////////////////////// WalletImpl implementation //////////////////////// @@ -302,6 +308,15 @@ std::string WalletImpl::address() const return m_wallet->get_account().get_public_address_str(m_wallet->testnet()); } +std::string WalletImpl::integratedAddress(const std::string &payment_id) const +{ + crypto::hash8 pid; + if (!tools::wallet2::parse_short_payment_id(payment_id, pid)) { + pid = crypto::rand<crypto::hash8>(); + } + return m_wallet->get_account().get_public_integrated_address_str(pid, m_wallet->testnet()); +} + bool WalletImpl::store(const std::string &path) { clearStatus(); @@ -380,31 +395,58 @@ bool WalletImpl::refresh() // - payment_details; // - unconfirmed_transfer_details; // - confirmed_transfer_details) -PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, uint64_t amount, uint32_t mixin_count) + +PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const string &payment_id, uint64_t amount, uint32_t mixin_count) { clearStatus(); vector<cryptonote::tx_destination_entry> dsts; cryptonote::tx_destination_entry de; - bool has_payment_id; - crypto::hash8 new_payment_id; + // indicates if dst_addr is integrated address (address + payment_id) + bool has_payment_id; + crypto::hash8 payment_id_short; // TODO: (https://bitcointalk.org/index.php?topic=753252.msg9985441#msg9985441) - size_t fake_outs_count = mixin_count > 0 ? mixin_count : m_wallet->default_mixin(); if (fake_outs_count == 0) fake_outs_count = DEFAULT_MIXIN; - PendingTransactionImpl * transaction = new PendingTransactionImpl(this); + PendingTransactionImpl * transaction = new PendingTransactionImpl(*this); do { - - if(!cryptonote::get_account_integrated_address_from_str(de.addr, has_payment_id, new_payment_id, m_wallet->testnet(), dst_addr)) { + if(!cryptonote::get_account_integrated_address_from_str(de.addr, has_payment_id, payment_id_short, m_wallet->testnet(), dst_addr)) { // TODO: copy-paste 'if treating as an address fails, try as url' from simplewallet.cpp:1982 m_status = Status_Error; m_errorString = "Invalid destination address"; break; } + + std::vector<uint8_t> extra; + // if dst_addr is not an integrated address, parse payment_id + if (!has_payment_id && !payment_id.empty()) { + // copy-pasted from simplewallet.cpp:2212 + crypto::hash payment_id_long; + bool r = tools::wallet2::parse_long_payment_id(payment_id, payment_id_long); + if (r) { + std::string extra_nonce; + cryptonote::set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id_long); + r = add_extra_nonce_to_tx_extra(extra, extra_nonce); + } else { + r = tools::wallet2::parse_short_payment_id(payment_id, payment_id_short); + if (r) { + std::string extra_nonce; + set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id_short); + r = add_extra_nonce_to_tx_extra(extra, extra_nonce); + } + } + + if (!r) { + m_status = Status_Error; + m_errorString = tr("payment id has invalid format, expected 16 or 64 character hex string: ") + payment_id; + break; + } + } + de.amount = amount; if (de.amount <= 0) { m_status = Status_Error; @@ -414,8 +456,6 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, uint64 dsts.push_back(de); //std::vector<tools::wallet2::pending_tx> ptx_vector; - std::vector<uint8_t> extra; - try { transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 016116e96..164aede1a 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -60,6 +60,7 @@ public: std::string errorString() const; bool setPassword(const std::string &password); std::string address() const; + std::string integratedAddress(const std::string &payment_id) const; bool store(const std::string &path); std::string filename() const; std::string keysFilename() const; @@ -70,7 +71,8 @@ public: uint64_t balance() const; uint64_t unlockedBalance() const; bool refresh(); - PendingTransaction * createTransaction(const std::string &dst_addr, uint64_t amount, uint32_t mixin_count); + PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id, + uint64_t amount, uint32_t mixin_count); virtual void disposeTransaction(PendingTransaction * t); virtual TransactionHistory * history() const; virtual void setListener(WalletListener * l); diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp index 3a97538b4..4ed6e09fb 100644 --- a/src/wallet/api/wallet_manager.cpp +++ b/src/wallet/api/wallet_manager.cpp @@ -85,7 +85,7 @@ bool WalletManagerImpl::walletExists(const std::string &path) std::vector<std::string> WalletManagerImpl::findWallets(const std::string &path) { std::vector<std::string> result; - const boost::regex wallet_rx("(.*)\\.(address\\.txt)$"); // searching for <wallet_name>.address.txt files + const boost::regex wallet_rx("(.*)\\.(keys)$"); // searching for <wallet_name>.keys files boost::filesystem::recursive_directory_iterator end_itr; // Default ctor yields past-the-end boost::filesystem::path work_dir(path); @@ -100,11 +100,9 @@ std::vector<std::string> WalletManagerImpl::findWallets(const std::string &path) bool matched = boost::regex_match(filename, what, wallet_rx); if (matched) { - // if address file found, checking if there's corresponding .keys file and wallet file itself + // if keys file found, checking if there's wallet file itself std::string wallet_file = (itr->path().parent_path() /= what[1]).string(); - std::string wallet_key_file = wallet_file + std::string(".keys"); - if (boost::filesystem::exists(wallet_file) - && boost::filesystem::exists(wallet_key_file)) { + if (boost::filesystem::exists(wallet_file)) { LOG_PRINT_L3("Found wallet: " << wallet_file); result.push_back(wallet_file); } diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 6f05929b4..02dd59862 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3081,7 +3081,6 @@ std::string wallet2::get_tx_note(const crypto::hash &txid) const return std::string(); return i->second; } - //---------------------------------------------------------------------------------------------------- void wallet2::generate_genesis(cryptonote::block& b) { if (m_testnet) diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index de0b50591..66987e4c5 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -134,6 +134,18 @@ struct Wallet virtual std::string errorString() const = 0; virtual bool setPassword(const std::string &password) = 0; virtual std::string address() const = 0; + + /*! + * \brief integratedAddress - returns integrated address for current wallet address and given payment_id. + * if passed "payment_id" param is an empty string or not-valid payment id string + * (16 characters hexadecimal string) - random payment_id will be generated + * + * \param payment_id - 16 characters hexadecimal string or empty string if new random payment id needs to be + * generated + * \return - 106 characters string representing integrated address + */ + virtual std::string integratedAddress(const std::string &payment_id) const = 0; + /*! * \brief store - stores wallet to file. * \param path - main filename to store wallet to. additionally stores address file and keys file. @@ -162,19 +174,24 @@ struct Wallet static std::string displayAmount(uint64_t amount); static uint64_t amountFromString(const std::string &amount); static uint64_t amountFromDouble(double amount); + static std::string genPaymentId(); // TODO? // virtual uint64_t unlockedDustBalance() const = 0; virtual bool refresh() = 0; /*! - * \brief createTransaction creates transaction + * \brief createTransaction creates transaction. if dst_addr is an integrated address, payment_id is ignored * \param dst_addr destination address as string + * \param payment_id optional payment_id, can be empty string * \param amount amount * \param mixin_count mixin count. if 0 passed, wallet will use default value * \return PendingTransaction object. caller is responsible to check PendingTransaction::status() * after object returned */ - virtual PendingTransaction * createTransaction(const std::string &dst_addr, uint64_t amount, uint32_t mixin_count) = 0; + + virtual PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id, + uint64_t amount, uint32_t mixin_count) = 0; + virtual void disposeTransaction(PendingTransaction * t) = 0; virtual TransactionHistory * history() const = 0; virtual void setListener(WalletListener *) = 0; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index a082f731b..5be9ae5b0 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -245,9 +245,9 @@ namespace tools m_wallet.commit_tx(ptx_vector); // populate response with tx hash - res.tx_hash = boost::lexical_cast<std::string>(cryptonote::get_transaction_hash(ptx_vector.back().tx)); + res.tx_hash = epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx_vector.back().tx)); if (req.get_tx_key) - res.tx_key = boost::lexical_cast<std::string>(ptx_vector.back().tx_key); + res.tx_key = epee::string_tools::pod_to_hex(ptx_vector.back().tx_key); return true; } catch (const tools::error::daemon_busy& e) @@ -308,9 +308,9 @@ namespace tools // populate response with tx hashes for (auto & ptx : ptx_vector) { - res.tx_hash_list.push_back(boost::lexical_cast<std::string>(cryptonote::get_transaction_hash(ptx.tx))); + res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx))); if (req.get_tx_keys) - res.tx_key_list.push_back(boost::lexical_cast<std::string>(ptx.tx_key)); + res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key)); } return true; @@ -354,9 +354,9 @@ namespace tools // populate response with tx hashes for (auto & ptx : ptx_vector) { - res.tx_hash_list.push_back(boost::lexical_cast<std::string>(cryptonote::get_transaction_hash(ptx.tx))); + res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx))); if (req.get_tx_keys) - res.tx_key_list.push_back(boost::lexical_cast<std::string>(ptx.tx_key)); + res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key)); } return true; @@ -413,9 +413,9 @@ namespace tools // populate response with tx hashes for (auto & ptx : ptx_vector) { - res.tx_hash_list.push_back(boost::lexical_cast<std::string>(cryptonote::get_transaction_hash(ptx.tx))); + res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx))); if (req.get_tx_keys) - res.tx_key_list.push_back(boost::lexical_cast<std::string>(ptx.tx_key)); + res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key)); } return true; @@ -493,7 +493,7 @@ namespace tools return false; } res.standard_address = get_account_address_as_str(m_wallet.testnet(),address); - res.payment_id = boost::lexical_cast<std::string>(payment_id); + res.payment_id = epee::string_tools::pod_to_hex(payment_id); return true; } catch (std::exception &e) @@ -686,7 +686,7 @@ namespace tools rpc_transfers.amount = td.amount(); rpc_transfers.spent = td.m_spent; rpc_transfers.global_index = td.m_global_output_index; - rpc_transfers.tx_hash = boost::lexical_cast<std::string>(cryptonote::get_transaction_hash(td.m_tx)); + rpc_transfers.tx_hash = epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(td.m_tx)); rpc_transfers.tx_size = txBlob.size(); res.transfers.push_back(rpc_transfers); } diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index ddd6969c6..f6f1b0832 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -62,12 +62,6 @@ const char * WALLET_LANG = "English"; const std::string WALLETS_ROOT_DIR = "/home/mbg033/dev/monero/testnet/"; -//const char * TESTNET_WALLET1_NAME = "/home/mbg033/dev/monero/testnet/wallet_01.bin"; -//const char * TESTNET_WALLET2_NAME = "/home/mbg033/dev/monero/testnet/wallet_02.bin"; -//const char * TESTNET_WALLET3_NAME = "/home/mbg033/dev/monero/testnet/wallet_03.bin"; -//const char * TESTNET_WALLET4_NAME = "/home/mbg033/dev/monero/testnet/wallet_04.bin"; -//const char * TESTNET_WALLET5_NAME = "/home/mbg033/dev/monero/testnet/wallet_05.bin"; - const std::string TESTNET_WALLET1_NAME = WALLETS_ROOT_DIR + "wallet_01.bin"; const std::string TESTNET_WALLET2_NAME = WALLETS_ROOT_DIR + "wallet_02.bin"; const std::string TESTNET_WALLET3_NAME = WALLETS_ROOT_DIR + "wallet_03.bin"; @@ -85,6 +79,8 @@ const uint64_t AMOUNT_10XMR = 10000000000000L; const uint64_t AMOUNT_5XMR = 5000000000000L; const uint64_t AMOUNT_1XMR = 1000000000000L; +const std::string PAYMENT_ID_EMPTY = ""; + } @@ -360,6 +356,23 @@ TEST_F(WalletManagerTest, WalletManagerFindsWallet) } +TEST_F(WalletManagerTest, WalletGeneratesPaymentId) +{ + std::string payment_id = Bitmonero::Wallet::genPaymentId(); + ASSERT_TRUE(payment_id.length() == 16); +} + + +TEST_F(WalletManagerTest, WalletGeneratesIntegratedAddress) +{ + std::string payment_id = Bitmonero::Wallet::genPaymentId(); + + Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); + std::string integrated_address = wallet1->integratedAddress(payment_id); + ASSERT_TRUE(integrated_address.length() == 106); +} + + TEST_F(WalletTest1, WalletShowsBalance) { // TODO: temporary disabled; @@ -439,6 +452,8 @@ TEST_F(WalletTest1, WalletTransactionWithMixin) mixins.push_back(20); mixins.push_back(25); + std::string payment_id = ""; + Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); @@ -452,7 +467,7 @@ TEST_F(WalletTest1, WalletTransactionWithMixin) for (auto mixin : mixins) { std::cerr << "Transaction mixin count: " << mixin << std::endl; Bitmonero::PendingTransaction * transaction = wallet1->createTransaction( - recepient_address, AMOUNT_5XMR, mixin); + recepient_address, payment_id, AMOUNT_5XMR, mixin); std::cerr << "Transaction status: " << transaction->status() << std::endl; std::cerr << "Transaction fee: " << Bitmonero::Wallet::displayAmount(transaction->fee()) << std::endl; @@ -504,7 +519,11 @@ TEST_F(WalletTest1, WalletTransactionAndHistory) std::string wallet4_addr = Utils::get_wallet_address(CURRENT_DST_WALLET, TESTNET_WALLET_PASS); - Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet4_addr, AMOUNT_10XMR * 5, 0); + + Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet4_addr, + PAYMENT_ID_EMPTY, + AMOUNT_10XMR * 5, 0); + ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok); ASSERT_TRUE(tx->commit()); history = wallet_src->history(); @@ -518,6 +537,55 @@ TEST_F(WalletTest1, WalletTransactionAndHistory) } } + +TEST_F(WalletTest1, WalletTransactionWithPaymentId) +{ + + Bitmonero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); + // make sure testnet daemon is running + ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0)); + ASSERT_TRUE(wallet_src->refresh()); + Bitmonero::TransactionHistory * history = wallet_src->history(); + history->refresh(); + ASSERT_TRUE(history->count() > 0); + size_t count1 = history->count(); + + std::cout << "**** Transactions before transfer (" << count1 << ")" << std::endl; + for (auto t: history->getAll()) { + ASSERT_TRUE(t != nullptr); + Utils::print_transaction(t); + } + + std::string wallet4_addr = Utils::get_wallet_address(CURRENT_DST_WALLET, TESTNET_WALLET_PASS); + + std::string payment_id = Bitmonero::Wallet::genPaymentId(); + ASSERT_TRUE(payment_id.length() == 16); + + + Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet4_addr, + payment_id, + AMOUNT_1XMR, 1); + + ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok); + ASSERT_TRUE(tx->commit()); + history = wallet_src->history(); + history->refresh(); + ASSERT_TRUE(count1 != history->count()); + + bool payment_id_in_history = false; + + std::cout << "**** Transactions after transfer (" << history->count() << ")" << std::endl; + for (auto t: history->getAll()) { + ASSERT_TRUE(t != nullptr); + Utils::print_transaction(t); + if (t->paymentId() == payment_id) { + payment_id_in_history = true; + } + } + + ASSERT_TRUE(payment_id_in_history); +} + struct MyWalletListener : public Bitmonero::WalletListener { diff --git a/tests/unit_tests/hardfork.cpp b/tests/unit_tests/hardfork.cpp index 6d4a100df..1d1f85945 100644 --- a/tests/unit_tests/hardfork.cpp +++ b/tests/unit_tests/hardfork.cpp @@ -129,7 +129,9 @@ public: return starting_height[version]; } virtual void set_hard_fork_version(uint64_t height, uint8_t version) { - if (versions.size() <= height) versions.resize(height+1); versions[height] = version; + if (versions.size() <= height) + versions.resize(height+1); + versions[height] = version; } virtual uint8_t get_hard_fork_version(uint64_t height) const { return versions[height]; |