diff --git a/.gitignore b/.gitignore index 5a867244..0b147270 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,7 @@ /build /tags .idea +.ycm_extra_conf.py +.ycm_extra_conf.pyc +Release +Debug diff --git a/CMakeLists.txt b/CMakeLists.txt index 8aa392ad..e5dc35f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,8 +83,8 @@ else() set(RELEASE_FLAGS "-Ofast -DNDEBUG -Wno-unused-variable") if(NOT APPLE) # There is a clang bug that does not allow to compile code that uses AES-NI intrinsics if -flto is enabled - if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND ${CMAKE_SYSTEM_NAME} STREQUAL "Linux" - AND ${CMAKE_BUILD_TYPE} STREQUAL "Release" AND ((CMAKE_C_COMPILER_VERSION VERSION_GREATER 4.9) OR (CMAKE_C_COMPILER_VERSION VERSION_EQUAL 4.9))) + if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_SYSTEM_NAME STREQUAL "Linux" + AND CMAKE_BUILD_TYPE STREQUAL "Release" AND ((CMAKE_C_COMPILER_VERSION VERSION_GREATER 4.9) OR (CMAKE_C_COMPILER_VERSION VERSION_EQUAL 4.9))) # On linux, to build in lto mode, check that ld.gold linker is used: 'update-alternatives --install /usr/bin/ld ld /usr/bin/ld.gold HIGHEST_PRIORITY' set(CMAKE_AR gcc-ar) set(CMAKE_RANLIB gcc-ranlib) diff --git a/src/CryptoNoteConfig.h b/src/CryptoNoteConfig.h index 17b3d14b..9bb8d360 100644 --- a/src/CryptoNoteConfig.h +++ b/src/CryptoNoteConfig.h @@ -155,7 +155,8 @@ const CheckpointData CHECKPOINTS[] = { {780000, "8dd55a9bae429e3685b90317281e633917023d3512eb7f37372209d1a5fc1070"}, {785500, "de1a487d70964d25ed6f7de196866f357a293e867ee81313e7fd0352d0126bdd"}, {789000, "acef490bbccce3b7b7ae8554a414f55413fbf4ca1472c6359b126a4439bd9f01"}, - {796000, "04e387a00d35db21d4d93d04040b31f22573972a7e61d72cc07d0ab69bcb9c44"} + {796000, "04e387a00d35db21d4d93d04040b31f22573972a7e61d72cc07d0ab69bcb9c44"}, + {800000, "d7fa4eea02e5ce60b949136569c0ea7ac71ea46e0065311054072ac415560b86"} }; } // CryptoNote diff --git a/src/CryptoNoteCore/Core.cpp b/src/CryptoNoteCore/Core.cpp index 3e51e7cc..a2f1553a 100755 --- a/src/CryptoNoteCore/Core.cpp +++ b/src/CryptoNoteCore/Core.cpp @@ -261,7 +261,7 @@ bool core::check_tx_semantic(const Transaction& tx, bool keeped_by_block) { get_inputs_money_amount(tx, amount_in); uint64_t amount_out = get_outs_money_amount(tx); - if (amount_in <= amount_out) { + if (amount_in < amount_out) { logger(ERROR) << "tx with wrong amounts: ins " << amount_in << ", outs " << amount_out << ", rejected for tx id= " << getObjectHash(tx); return false; } diff --git a/src/CryptoNoteCore/TransactionPool.cpp b/src/CryptoNoteCore/TransactionPool.cpp index 4c74e070..e4d1552c 100644 --- a/src/CryptoNoteCore/TransactionPool.cpp +++ b/src/CryptoNoteCore/TransactionPool.cpp @@ -126,7 +126,7 @@ namespace CryptoNote { uint64_t outputs_amount = get_outs_money_amount(tx); - if (outputs_amount >= inputs_amount) { + if (outputs_amount > inputs_amount) { logger(INFO) << "transaction use more money then it has: use " << m_currency.formatAmount(outputs_amount) << ", have " << m_currency.formatAmount(inputs_amount); tvc.m_verifivation_failed = true; diff --git a/src/PaymentGate/WalletService.cpp b/src/PaymentGate/WalletService.cpp index 68dfaf88..17607514 100755 --- a/src/PaymentGate/WalletService.cpp +++ b/src/PaymentGate/WalletService.cpp @@ -23,15 +23,7 @@ #include #include -#ifdef WIN32 -#ifndef NOMINMAX -#define NOMINMAX -#endif -#include -#else -#include -#include -#endif +#include #include #include @@ -114,11 +106,8 @@ std::string createTemporaryFile(const std::string& path, std::fstream& tempFile) //returns true on success bool deleteFile(const std::string& filename) { -#ifdef WIN32 - return DeleteFile(filename.c_str()) != 0; -#else - return unlink(filename.c_str()) == 0; -#endif + boost::system::error_code err; + return boost::filesystem::remove(filename, err) && !err; } void replaceWalletFiles(const std::string &path, const std::string &tempFilePath) { diff --git a/src/Platform/Linux/System/Dispatcher.cpp b/src/Platform/Linux/System/Dispatcher.cpp index 28f5f0de..4a1ae025 100755 --- a/src/Platform/Linux/System/Dispatcher.cpp +++ b/src/Platform/Linux/System/Dispatcher.cpp @@ -25,6 +25,7 @@ #include #include #include +#include "ErrorMessage.h" namespace System { @@ -40,7 +41,7 @@ public: MutextGuard(pthread_mutex_t& _mutex) : mutex(_mutex) { auto ret = pthread_mutex_lock(&mutex); if (ret != 0) { - throw std::runtime_error("failed to acquire mutex, errno=" + std::to_string(ret) + ": " + strerror(ret)); + throw std::runtime_error("pthread_mutex_lock failed, " + errorMessage(ret)); } } @@ -62,15 +63,15 @@ Dispatcher::Dispatcher() { std::string message; epoll = ::epoll_create1(0); if (epoll == -1) { - message = "epoll_create1() fail errno=" + std::to_string(errno); + message = "epoll_create1 failed, " + lastErrorMessage(); } else { mainContext.ucontext = new ucontext_t; if (getcontext(reinterpret_cast(mainContext.ucontext)) == -1) { - message = "getcontext() fail errno=" + std::to_string(errno); + message = "getcontext failed, " + lastErrorMessage(); } else { remoteSpawnEvent = eventfd(0, O_NONBLOCK); if(remoteSpawnEvent == -1) { - message = "eventfd() fail errno=" + std::to_string(errno); + message = "eventfd failed, " + lastErrorMessage(); } else { remoteSpawnEventContext.writeContext = nullptr; remoteSpawnEventContext.readContext = nullptr; @@ -80,7 +81,7 @@ Dispatcher::Dispatcher() { remoteSpawnEventEpollEvent.data.ptr = &remoteSpawnEventContext; if (epoll_ctl(epoll, EPOLL_CTL_ADD, remoteSpawnEvent, &remoteSpawnEventEpollEvent) == -1) { - message = "epoll_ctl() failed, errno=" + std::to_string(errno); + message = "epoll_ctl failed, " + lastErrorMessage(); } else { *reinterpret_cast(this->mutex) = pthread_mutex_t(PTHREAD_MUTEX_INITIALIZER); @@ -155,7 +156,7 @@ void Dispatcher::clear() { while (!timers.empty()) { int result = ::close(timers.top()); if (result == -1) { - throw std::runtime_error("Dispatcher::clear, close failed, errno=" + std::to_string(errno)); + throw std::runtime_error("Dispatcher::clear, close failed, " + lastErrorMessage()); } timers.pop(); @@ -179,7 +180,7 @@ void Dispatcher::dispatch() { uint64_t buf; auto transferred = read(remoteSpawnEvent, &buf, sizeof buf); if(transferred == -1) { - throw std::runtime_error("Dispatcher::dispatch() read(remoteSpawnEvent) fail errno=" + std::to_string(errno)); + throw std::runtime_error("Dispatcher::dispatch, read(remoteSpawnEvent) failed, " + lastErrorMessage()); } MutextGuard guard(*reinterpret_cast(this->mutex)); @@ -206,7 +207,7 @@ void Dispatcher::dispatch() { } if (errno != EINTR) { - throw std::runtime_error("Dispatcher::dispatch(), epoll_wait() failed, errno=" + std::to_string(errno)); + throw std::runtime_error("Dispatcher::dispatch, epoll_wait failed, " + lastErrorMessage()); } } @@ -214,7 +215,7 @@ void Dispatcher::dispatch() { ucontext_t* oldContext = static_cast(currentContext->ucontext); currentContext = context; if (swapcontext(oldContext, static_cast(context->ucontext)) == -1) { - throw std::runtime_error("Dispatcher::dispatch() swapcontext() failed, errno=" + std::to_string(errno)); + throw std::runtime_error("Dispatcher::dispatch, swapcontext failed, " + lastErrorMessage()); } } } @@ -269,7 +270,7 @@ void Dispatcher::remoteSpawn(std::function&& procedure) { uint64_t one = 1; auto transferred = write(remoteSpawnEvent, &one, sizeof one); if(transferred == - 1) { - throw std::runtime_error("Dispatcher::remoteSpawn, write() failed errno = " + std::to_string(errno)); + throw std::runtime_error("Dispatcher::remoteSpawn, write failed, " + lastErrorMessage()); } } @@ -308,7 +309,7 @@ void Dispatcher::yield() { uint64_t buf; auto transferred = read(remoteSpawnEvent, &buf, sizeof buf); if(transferred == -1) { - throw std::runtime_error("Dispatcher::dispatch() read(remoteSpawnEvent) fail errno=" + std::to_string(errno)); + throw std::runtime_error("Dispatcher::dispatch, read(remoteSpawnEvent) failed, " + lastErrorMessage()); } MutextGuard guard(*reinterpret_cast(this->mutex)); @@ -334,7 +335,7 @@ void Dispatcher::yield() { } } else { if (errno != EINTR) { - throw std::runtime_error("Dispatcher::dispatch(), epoll_wait() failed, errno=" + std::to_string(errno)); + throw std::runtime_error("Dispatcher::dispatch, epoll_wait failed, " + lastErrorMessage()); } } } @@ -353,7 +354,7 @@ NativeContext& Dispatcher::getReusableContext() { if(firstReusableContext == nullptr) { ucontext_t* newlyCreatedContext = new ucontext_t; if (getcontext(newlyCreatedContext) == -1) { //makecontext precondition - throw std::runtime_error("Dispatcher::getReusableContext(), getcontext() fail errno=" + std::to_string(errno)); + throw std::runtime_error("Dispatcher::getReusableContext, getcontext failed, " + lastErrorMessage()); } auto stackPointer = new uint8_t[STACK_SIZE]; @@ -365,7 +366,7 @@ NativeContext& Dispatcher::getReusableContext() { ucontext_t* oldContext = static_cast(currentContext->ucontext); if (swapcontext(oldContext, newlyCreatedContext) == -1) { - throw std::runtime_error("Dispatcher::getReusableContext() swapcontext() failed, errno=" + std::to_string(errno)); + throw std::runtime_error("Dispatcher::getReusableContext, swapcontext failed, " + lastErrorMessage()); } assert(firstReusableContext != nullptr); @@ -393,7 +394,7 @@ int Dispatcher::getTimer() { timerEvent.data.ptr = nullptr; if (epoll_ctl(getEpoll(), EPOLL_CTL_ADD, timer, &timerEvent) == -1) { - throw std::runtime_error("Dispatcher::getTimer(), epoll_ctl() failed, errno=" + std::to_string(errno)); + throw std::runtime_error("Dispatcher::getTimer, epoll_ctl failed, " + lastErrorMessage()); } } else { timer = timers.top(); @@ -416,7 +417,7 @@ void Dispatcher::contextProcedure(void* ucontext) { firstReusableContext = &context; ucontext_t* oldContext = static_cast(context.ucontext); if (swapcontext(oldContext, static_cast(currentContext->ucontext)) == -1) { - throw std::runtime_error("Dispatcher::contextProcedure() swapcontext() failed, errno=" + std::to_string(errno)); + throw std::runtime_error("Dispatcher::contextProcedure, swapcontext failed, " + lastErrorMessage()); } for (;;) { diff --git a/src/Platform/Linux/System/ErrorMessage.cpp b/src/Platform/Linux/System/ErrorMessage.cpp new file mode 100644 index 00000000..75df8c14 --- /dev/null +++ b/src/Platform/Linux/System/ErrorMessage.cpp @@ -0,0 +1,32 @@ +// Copyright (c) 2012-2015, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#include "ErrorMessage.h" +#include +#include + +namespace System { + +std::string lastErrorMessage() { + return errorMessage(errno); +} + +std::string errorMessage(int err) { + return "result=" + std::to_string(err) + ", " + std::strerror(err); +} + +} diff --git a/src/Platform/Linux/System/ErrorMessage.h b/src/Platform/Linux/System/ErrorMessage.h new file mode 100644 index 00000000..ffe88ed3 --- /dev/null +++ b/src/Platform/Linux/System/ErrorMessage.h @@ -0,0 +1,25 @@ +// Copyright (c) 2012-2015, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#pragma once + +#include + +namespace System { +std::string lastErrorMessage(); +std::string errorMessage(int); +} diff --git a/src/Platform/Linux/System/Ipv4Resolver.cpp b/src/Platform/Linux/System/Ipv4Resolver.cpp index b9f1e435..cbb8b370 100755 --- a/src/Platform/Linux/System/Ipv4Resolver.cpp +++ b/src/Platform/Linux/System/Ipv4Resolver.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -62,7 +63,7 @@ Ipv4Address Ipv4Resolver::resolve(const std::string& host) { addrinfo* addressInfos; int result = getaddrinfo(host.c_str(), NULL, &hints, &addressInfos); if (result != 0) { - throw std::runtime_error("Ipv4Resolver::resolve, getaddrinfo failed, result=" + std::to_string(result)); + throw std::runtime_error("Ipv4Resolver::resolve, getaddrinfo failed, " + errorMessage(result)); } std::size_t count = 0; diff --git a/src/Platform/Linux/System/TcpConnection.cpp b/src/Platform/Linux/System/TcpConnection.cpp index cce62459..07165357 100755 --- a/src/Platform/Linux/System/TcpConnection.cpp +++ b/src/Platform/Linux/System/TcpConnection.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -54,7 +55,7 @@ TcpConnection& TcpConnection::operator=(TcpConnection&& other) { assert(contextPair.readContext == nullptr); assert(contextPair.writeContext == nullptr); if (close(connection) == -1) { - throw std::runtime_error("TcpConnection::operator=, close() failed, errno=" + std::to_string(errno)); + throw std::runtime_error("TcpConnection::operator=, close failed, " + lastErrorMessage()); } } @@ -81,7 +82,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) { ssize_t transferred = ::recv(connection, (void *)data, size, 0); if (transferred == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { - message = "recv failed, errno=" + std::to_string(errno); + message = "recv failed, " + lastErrorMessage(); } else { epoll_event connectionEvent; OperationContext operationContext; @@ -97,7 +98,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) { } if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, connection, &connectionEvent) == -1) { - message = "epoll_ctl() failed, errno=" + std::to_string(errno); + message = "epoll_ctl failed, " + lastErrorMessage(); } else { dispatcher->getCurrentContext()->interruptProcedure = [&]() { assert(dispatcher != nullptr); @@ -107,7 +108,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) { connectionEvent.data.ptr = nullptr; if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, connection, &connectionEvent) == -1) { - throw std::runtime_error("TcpConnection::stop, epoll_ctl() fail, errno=" + std::to_string(errno)); + throw std::runtime_error("TcpConnection::stop, epoll_ctl failed, " + lastErrorMessage()); } contextPair.readContext->interrupted = true; @@ -132,7 +133,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) { connectionEvent.data.ptr = &contextPair; if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, connection, &connectionEvent) == -1) { - message = "epoll_ctl() failed, errno=" + std::to_string(errno); + message = "epoll_ctl failed, " + lastErrorMessage(); throw std::runtime_error("TcpConnection::read"); } } @@ -143,7 +144,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) { ssize_t transferred = ::recv(connection, (void *)data, size, 0); if (transferred == -1) { - message = "recv failed, errno=" + std::to_string(errno); + message = "recv failed, " + lastErrorMessage(); } else { assert(transferred <= static_cast(size)); return transferred; @@ -168,7 +169,7 @@ std::size_t TcpConnection::write(const uint8_t* data, size_t size) { std::string message; if(size == 0) { if(shutdown(connection, SHUT_WR) == -1) { - throw std::runtime_error("TcpConnection::write, shutdown failed, result=" + std::to_string(errno)); + throw std::runtime_error("TcpConnection::write, shutdown failed, " + lastErrorMessage()); } return 0; @@ -177,7 +178,7 @@ std::size_t TcpConnection::write(const uint8_t* data, size_t size) { ssize_t transferred = ::send(connection, (void *)data, size, MSG_NOSIGNAL); if (transferred == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { - message = "send failed, result=" + std::to_string(errno); + message = "send failed, " + lastErrorMessage(); } else { epoll_event connectionEvent; OperationContext operationContext; @@ -193,7 +194,7 @@ std::size_t TcpConnection::write(const uint8_t* data, size_t size) { } if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, connection, &connectionEvent) == -1) { - message = "epoll_ctl() failed, errno=" + std::to_string(errno); + message = "epoll_ctl failed, " + lastErrorMessage(); } else { dispatcher->getCurrentContext()->interruptProcedure = [&]() { assert(dispatcher != nullptr); @@ -203,7 +204,7 @@ std::size_t TcpConnection::write(const uint8_t* data, size_t size) { connectionEvent.data.ptr = nullptr; if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, connection, &connectionEvent) == -1) { - throw std::runtime_error("TcpConnection::stop, epoll_ctl() fail" + std::to_string(errno)); + throw std::runtime_error("TcpConnection::stop, epoll_ctl failed, " + lastErrorMessage()); } contextPair.writeContext->interrupted = true; @@ -228,18 +229,18 @@ std::size_t TcpConnection::write(const uint8_t* data, size_t size) { connectionEvent.data.ptr = &contextPair; if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, connection, &connectionEvent) == -1) { - message = "epoll_ctl() failed, errno=" + std::to_string(errno); + message = "epoll_ctl failed, " + lastErrorMessage(); throw std::runtime_error("TcpConnection::write, " + message); } } if((operationContext.events & (EPOLLERR | EPOLLHUP)) != 0) { - throw std::runtime_error("TcpConnection::write: events & (EPOLLERR | EPOLLHUP) != 0"); + throw std::runtime_error("TcpConnection::write, events & (EPOLLERR | EPOLLHUP) != 0"); } ssize_t transferred = ::send(connection, (void *)data, size, 0); if (transferred == -1) { - message = "send failed, errno=" + std::to_string(errno); + message = "send failed, " + lastErrorMessage(); } else { assert(transferred <= static_cast(size)); return transferred; @@ -258,7 +259,7 @@ std::pair TcpConnection::getPeerAddressAndPort() const { sockaddr_in addr; socklen_t size = sizeof(addr); if (getpeername(connection, reinterpret_cast(&addr), &size) != 0) { - throw std::runtime_error("TcpConnection::getPeerAddress, getpeername failed, errno=" + std::to_string(errno)); + throw std::runtime_error("TcpConnection::getPeerAddress, getpeername failed, " + lastErrorMessage()); } assert(size == sizeof(sockaddr_in)); @@ -273,7 +274,7 @@ TcpConnection::TcpConnection(Dispatcher& dispatcher, int socket) : dispatcher(&d connectionEvent.data.ptr = nullptr; if (epoll_ctl(dispatcher.getEpoll(), EPOLL_CTL_ADD, socket, &connectionEvent) == -1) { - throw std::runtime_error("TcpConnection::TcpConnection, epoll_ctl() fail, errno=" + std::to_string(errno)); + throw std::runtime_error("TcpConnection::TcpConnection, epoll_ctl failed, " + lastErrorMessage()); } } diff --git a/src/Platform/Linux/System/TcpConnector.cpp b/src/Platform/Linux/System/TcpConnector.cpp index 76d577fb..8616241a 100755 --- a/src/Platform/Linux/System/TcpConnector.cpp +++ b/src/Platform/Linux/System/TcpConnector.cpp @@ -27,6 +27,7 @@ #include #include #include "Dispatcher.h" +#include "ErrorMessage.h" #include "TcpConnection.h" namespace System { @@ -77,18 +78,18 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) { std::string message; int connection = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (connection == -1) { - message = "socket() failed, errno=" + std::to_string(errno); + message = "socket failed, " + lastErrorMessage(); } else { sockaddr_in bindAddress; bindAddress.sin_family = AF_INET; bindAddress.sin_port = 0; bindAddress.sin_addr.s_addr = INADDR_ANY; if (bind(connection, reinterpret_cast(&bindAddress), sizeof bindAddress) != 0) { - message = "bind failed, errno=" + std::to_string(errno); + message = "bind failed, " + lastErrorMessage(); } else { int flags = fcntl(connection, F_GETFL, 0); if (flags == -1 || fcntl(connection, F_SETFL, flags | O_NONBLOCK) == -1) { - message = "fcntl() failed errno=" + std::to_string(errno); + message = "fcntl failed, " + lastErrorMessage(); } else { sockaddr_in addressData; addressData.sin_family = AF_INET; @@ -111,14 +112,14 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) { connectEvent.events = EPOLLOUT | EPOLLRDHUP | EPOLLERR | EPOLLONESHOT; connectEvent.data.ptr = &contextPair; if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_ADD, connection, &connectEvent) == -1) { - message = "epoll_ctl() failed, errno=" + std::to_string(errno); + message = "epoll_ctl failed, " + lastErrorMessage(); } else { context = &connectorContext; dispatcher->getCurrentContext()->interruptProcedure = [&] { TcpConnectorContextExt* connectorContext1 = static_cast(context); if (!connectorContext1->interrupted) { if (close(connectorContext1->connection) == -1) { - throw std::runtime_error("TcpListener::stop, close failed, errno=" + std::to_string(errno)); + throw std::runtime_error("TcpListener::stop, close failed, " + lastErrorMessage()); } connectorContext1->interrupted = true; @@ -139,7 +140,7 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) { } if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_DEL, connection, NULL) == -1) { - message = "epoll_ctl() failed, errno=" + std::to_string(errno); + message = "epoll_ctl failed, " + lastErrorMessage(); } else { if((connectorContext.events & (EPOLLERR | EPOLLHUP)) != 0) { int result = close(connection); @@ -152,10 +153,10 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) { socklen_t retValLen = sizeof(retval); int s = getsockopt(connection, SOL_SOCKET, SO_ERROR, &retval, &retValLen); if (s == -1) { - message = "getsockopt() failed, errno=" + std::to_string(errno); + message = "getsockopt failed, " + lastErrorMessage(); } else { if (retval != 0) { - message = "connect failed; getsockopt retval =" + std::to_string(errno); + message = "getsockopt failed, " + lastErrorMessage(); } else { return TcpConnection(*dispatcher, connection); } diff --git a/src/Platform/Linux/System/TcpListener.cpp b/src/Platform/Linux/System/TcpListener.cpp index fde904b7..53b4ca63 100755 --- a/src/Platform/Linux/System/TcpListener.cpp +++ b/src/Platform/Linux/System/TcpListener.cpp @@ -27,6 +27,7 @@ #include "Dispatcher.h" #include "TcpConnection.h" +#include #include #include @@ -39,31 +40,31 @@ TcpListener::TcpListener(Dispatcher& dispatcher, const Ipv4Address& addr, uint16 std::string message; listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (listener == -1) { - message = "socket() failed, errno=" + std::to_string(errno) + ": " + strerror(errno); + message = "socket failed, " + lastErrorMessage(); } else { int flags = fcntl(listener, F_GETFL, 0); if (flags == -1 || fcntl(listener, F_SETFL, flags | O_NONBLOCK) == -1) { - message = "fcntl() failed errno=" + std::to_string(errno) + ": " + strerror(errno); + message = "fcntl failed, " + lastErrorMessage(); } else { int on = 1; if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on) == -1) { - message = "setsockopt failed, errno=" + std::to_string(errno) + ": " + strerror(errno); + message = "setsockopt failed, " + lastErrorMessage(); } else { sockaddr_in address; address.sin_family = AF_INET; address.sin_port = htons(port); address.sin_addr.s_addr = htonl( addr.getValue()); if (bind(listener, reinterpret_cast(&address), sizeof address) != 0) { - message = "bind failed, errno=" + std::to_string(errno) + ": " + strerror(errno); + message = "bind failed, " + lastErrorMessage(); } else if (listen(listener, SOMAXCONN) != 0) { - message = "listen failed, errno=" + std::to_string(errno) + ": " + strerror(errno); + message = "listen failed, " + lastErrorMessage(); } else { epoll_event listenEvent; listenEvent.events = 0; listenEvent.data.ptr = nullptr; if (epoll_ctl(dispatcher.getEpoll(), EPOLL_CTL_ADD, listener, &listenEvent) == -1) { - message = "epoll_ctl() failed, errno=" + std::to_string(errno) + ": " + strerror(errno); + message = "epoll_ctl failed, " + lastErrorMessage(); } else { context = nullptr; return; @@ -100,7 +101,7 @@ TcpListener& TcpListener::operator=(TcpListener&& other) { if (dispatcher != nullptr) { assert(context == nullptr); if (close(listener) == -1) { - throw std::runtime_error("TcpListener::operator=, close failed, errno=" + std::to_string(errno)); + throw std::runtime_error("TcpListener::operator=, close failed, " + lastErrorMessage()); } } @@ -135,7 +136,7 @@ TcpConnection TcpListener::accept() { listenEvent.data.ptr = &contextPair; std::string message; if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, listener, &listenEvent) == -1) { - message = "epoll_ctl() failed, errno=" + std::to_string(errno); + message = "epoll_ctl failed, " + lastErrorMessage(); } else { context = &listenerContext; dispatcher->getCurrentContext()->interruptProcedure = [&]() { @@ -148,7 +149,7 @@ TcpConnection TcpListener::accept() { listenEvent.data.ptr = nullptr; if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, listener, &listenEvent) == -1) { - throw std::runtime_error("TcpListener::stop, epoll_ctl() failed, errno=" + std::to_string(errno) ); + throw std::runtime_error("TcpListener::stop, epoll_ctl failed, " + lastErrorMessage() ); } listenerContext->interrupted = true; @@ -176,11 +177,11 @@ TcpConnection TcpListener::accept() { socklen_t inLen = sizeof(inAddr); int connection = ::accept(listener, &inAddr, &inLen); if (connection == -1) { - message = "accept() failed, errno=" + std::to_string(errno); + message = "accept failed, " + lastErrorMessage(); } else { int flags = fcntl(connection, F_GETFL, 0); if (flags == -1 || fcntl(connection, F_SETFL, flags | O_NONBLOCK) == -1) { - message = "fcntl() failed errno=" + std::to_string(errno); + message = "fcntl failed, " + lastErrorMessage(); } else { return TcpConnection(*dispatcher, connection); } diff --git a/src/Platform/Linux/System/Timer.cpp b/src/Platform/Linux/System/Timer.cpp index 6cc0a350..03e1cfcf 100755 --- a/src/Platform/Linux/System/Timer.cpp +++ b/src/Platform/Linux/System/Timer.cpp @@ -24,6 +24,7 @@ #include #include "Dispatcher.h" +#include #include namespace System { @@ -92,7 +93,7 @@ void Timer::sleep(std::chrono::nanoseconds duration) { timerEvent.data.ptr = &contextPair; if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, timer, &timerEvent) == -1) { - throw std::runtime_error("Timer::sleep, epoll_ctl() failed, errno=" + std::to_string(errno)); + throw std::runtime_error("Timer::sleep, epoll_ctl failed, " + lastErrorMessage()); } dispatcher->getCurrentContext()->interruptProcedure = [&]() { assert(dispatcher != nullptr); @@ -105,7 +106,7 @@ void Timer::sleep(std::chrono::nanoseconds duration) { timerContext->interrupted = true; dispatcher->pushContext(timerContext->context); } else { - throw std::runtime_error("Timer::interrupt, read failed, errno=" + std::to_string(errno)); + throw std::runtime_error("Timer::interrupt, read failed, " + lastErrorMessage()); } } else { assert(value>0); @@ -117,7 +118,7 @@ void Timer::sleep(std::chrono::nanoseconds duration) { timerEvent.data.ptr = nullptr; if (epoll_ctl(dispatcher->getEpoll(), EPOLL_CTL_MOD, timer, &timerEvent) == -1) { - throw std::runtime_error("Timer::interrupt epoll_ctl() failed, errno=" + std::to_string(errno)); + throw std::runtime_error("Timer::interrupt, epoll_ctl failed, " + lastErrorMessage()); } } }; diff --git a/src/Platform/OSX/System/Dispatcher.cpp b/src/Platform/OSX/System/Dispatcher.cpp index 619200fa..d7d9664d 100755 --- a/src/Platform/OSX/System/Dispatcher.cpp +++ b/src/Platform/OSX/System/Dispatcher.cpp @@ -27,6 +27,7 @@ #include #include #include "Context.h" +#include "ErrorMessage.h" namespace System { @@ -42,7 +43,7 @@ public: MutextGuard(pthread_mutex_t& _mutex) : mutex(_mutex) { auto ret = pthread_mutex_lock(&mutex); if (ret != 0) { - throw std::runtime_error("failed to acquire mutex, errno=" + std::to_string(ret) + ": " + strerror(ret)); + throw std::runtime_error("MutextGuard::MutextGuard, pthread_mutex_lock failed, " + errorMessage(ret)); } } @@ -64,19 +65,19 @@ Dispatcher::Dispatcher() : lastCreatedTimer(0) { std::string message; kqueue = ::kqueue(); if (kqueue == -1) { - message = "kqueue() fail errno=" + std::to_string(errno); + message = "kqueue failed, " + lastErrorMessage(); } else { mainContext.uctx = new uctx; if (getcontext(static_cast(mainContext.uctx)) == -1) { - message = "getcontext() fail errno=" + std::to_string(errno); + message = "getcontext failed, " + lastErrorMessage(); } else { struct kevent event; EV_SET(&event, 0, EVFILT_USER, EV_ADD, NOTE_FFNOP, 0, NULL); if (kevent(kqueue, &event, 1, NULL, 0, NULL) == -1) { - message = "kevent() fail errno=" + std::to_string(errno); + message = "kevent failed, " + lastErrorMessage(); } else { if(pthread_mutex_init(reinterpret_cast(this->mutex), NULL) == -1) { - message = "pthread_mutex_init() fail errno=" + std::to_string(errno); + message = "pthread_mutex_init failed, " + lastErrorMessage(); } else { remoteSpawned = false; @@ -165,7 +166,7 @@ void Dispatcher::dispatch() { struct kevent event; EV_SET(&event, 0, EVFILT_USER, EV_ADD | EV_DISABLE, NOTE_FFNOP, 0, NULL); if (kevent(kqueue, &event, 1, NULL, 0, NULL) == -1) { - throw std::runtime_error("kevent() fail errno=" + std::to_string(errno)); + throw std::runtime_error("Dispatcher::dispatch, kevent failed, " + lastErrorMessage()); } continue; @@ -176,7 +177,7 @@ void Dispatcher::dispatch() { } if (errno != EINTR) { - throw std::runtime_error("Dispatcher::dispatch(), kqueue() fail errno=" + std::to_string(errno)); + throw std::runtime_error("Dispatcher::dispatch, kqueue failed, " + lastErrorMessage()); } else { MutextGuard guard(*reinterpret_cast(this->mutex)); while (!remoteSpawningProcedures.empty()) { @@ -191,7 +192,7 @@ void Dispatcher::dispatch() { uctx* oldContext = static_cast(currentContext->uctx); currentContext = context; if (swapcontext(oldContext,static_cast(currentContext->uctx)) == -1) { - throw std::runtime_error("Dispatcher::dispatch(), swapcontext() failed, errno=" + std::to_string(errno)); + throw std::runtime_error("Dispatcher::dispatch, swapcontext failed, " + lastErrorMessage()); } } } @@ -246,7 +247,7 @@ void Dispatcher::remoteSpawn(std::function&& procedure) { struct kevent event; EV_SET(&event, 0, EVFILT_USER, EV_ADD | EV_ENABLE, NOTE_FFCOPY | NOTE_TRIGGER, 0, NULL); if (kevent(kqueue, &event, 1, NULL, 0, NULL) == -1) { - throw std::runtime_error("Dispatcher::remoteSpawn(), kevent() fail errno=" + std::to_string(errno)); + throw std::runtime_error("Dispatcher::remoteSpawn, kevent failed, " + lastErrorMessage()); }; } } @@ -286,7 +287,7 @@ void Dispatcher::yield() { struct kevent event; EV_SET(&event, 0, EVFILT_USER, EV_ADD | EV_DISABLE, NOTE_FFNOP, 0, NULL); if (kevent(kqueue, &event, 1, NULL, 0, NULL) == -1) { - throw std::runtime_error("kevent() fail errno=" + std::to_string(errno)); + throw std::runtime_error("Dispatcher::yield, kevent failed, " + lastErrorMessage()); } MutextGuard guard(*reinterpret_cast(this->mutex)); @@ -304,7 +305,7 @@ void Dispatcher::yield() { } } else { if (errno != EINTR) { - throw std::runtime_error("Dispatcher::dispatch(), epoll_wait() failed, errno=" + std::to_string(errno)); + throw std::runtime_error("Dispatcher::dispatch, kevent failed, " + lastErrorMessage()); } } } @@ -331,7 +332,7 @@ NativeContext& Dispatcher::getReusableContext() { uctx* oldContext = static_cast(currentContext->uctx); if (swapcontext(oldContext, newlyCreatedContext) == -1) { - throw std::runtime_error("Dispatcher::getReusableContext(), swapcontext() failed, errno=" + std::to_string(errno)); + throw std::runtime_error("Dispatcher::getReusableContext, swapcontext failed, " + lastErrorMessage()); } assert(firstReusableContext != nullptr); @@ -375,7 +376,7 @@ void Dispatcher::contextProcedure(void* ucontext) { firstReusableContext = &context; uctx* oldContext = static_cast(context.uctx); if (swapcontext(oldContext, static_cast(currentContext->uctx)) == -1) { - throw std::runtime_error("Dispatcher::contextProcedure() swapcontext() failed, errno=" + std::to_string(errno)); + throw std::runtime_error("Dispatcher::contextProcedure, swapcontext failed, " + lastErrorMessage()); } for (;;) { diff --git a/src/Platform/OSX/System/ErrorMessage.cpp b/src/Platform/OSX/System/ErrorMessage.cpp new file mode 100644 index 00000000..75df8c14 --- /dev/null +++ b/src/Platform/OSX/System/ErrorMessage.cpp @@ -0,0 +1,32 @@ +// Copyright (c) 2012-2015, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#include "ErrorMessage.h" +#include +#include + +namespace System { + +std::string lastErrorMessage() { + return errorMessage(errno); +} + +std::string errorMessage(int err) { + return "result=" + std::to_string(err) + ", " + std::strerror(err); +} + +} diff --git a/src/Platform/OSX/System/ErrorMessage.h b/src/Platform/OSX/System/ErrorMessage.h new file mode 100644 index 00000000..ffe88ed3 --- /dev/null +++ b/src/Platform/OSX/System/ErrorMessage.h @@ -0,0 +1,25 @@ +// Copyright (c) 2012-2015, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#pragma once + +#include + +namespace System { +std::string lastErrorMessage(); +std::string errorMessage(int); +} diff --git a/src/Platform/OSX/System/Ipv4Resolver.cpp b/src/Platform/OSX/System/Ipv4Resolver.cpp index b9f1e435..cbb8b370 100755 --- a/src/Platform/OSX/System/Ipv4Resolver.cpp +++ b/src/Platform/OSX/System/Ipv4Resolver.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -62,7 +63,7 @@ Ipv4Address Ipv4Resolver::resolve(const std::string& host) { addrinfo* addressInfos; int result = getaddrinfo(host.c_str(), NULL, &hints, &addressInfos); if (result != 0) { - throw std::runtime_error("Ipv4Resolver::resolve, getaddrinfo failed, result=" + std::to_string(result)); + throw std::runtime_error("Ipv4Resolver::resolve, getaddrinfo failed, " + errorMessage(result)); } std::size_t count = 0; diff --git a/src/Platform/OSX/System/TcpConnection.cpp b/src/Platform/OSX/System/TcpConnection.cpp index 112c2d59..8d85d991 100755 --- a/src/Platform/OSX/System/TcpConnection.cpp +++ b/src/Platform/OSX/System/TcpConnection.cpp @@ -25,6 +25,7 @@ #include #include "Dispatcher.h" +#include #include #include @@ -58,7 +59,7 @@ TcpConnection& TcpConnection::operator=(TcpConnection&& other) { assert(readContext == nullptr); assert(writeContext == nullptr); if (close(connection) == -1) { - throw std::runtime_error("TcpConnection::operator=, close() failed, errno=" + std::to_string(errno)); + throw std::runtime_error("TcpConnection::operator=, close failed, " + lastErrorMessage()); } } @@ -86,7 +87,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) { ssize_t transferred = ::recv(connection, (void *)data, size, 0); if (transferred == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { - message = "recv failed, errno=" + std::to_string(errno); + message = "recv failed, " + lastErrorMessage(); } else { OperationContext context; context.context = dispatcher->getCurrentContext(); @@ -94,7 +95,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) { struct kevent event; EV_SET(&event, connection, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR | EV_ONESHOT, 0, 0, &context); if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) { - message = "kevent() failed, errno=" + std::to_string(errno); + message = "kevent failed, " + lastErrorMessage(); } else { readContext = &context; dispatcher->getCurrentContext()->interruptProcedure = [&] { @@ -106,7 +107,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) { EV_SET(&event, connection, EVFILT_READ, EV_DELETE | EV_DISABLE, 0, 0, NULL); if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) { - throw std::runtime_error("TcpListener::interruptionProcedure, kevent() failed, errno=" + std::to_string(errno)); + throw std::runtime_error("TcpListener::interruptionProcedure, kevent failed, " + lastErrorMessage()); } context->interrupted = true; @@ -127,7 +128,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) { ssize_t transferred = ::recv(connection, (void *)data, size, 0); if (transferred == -1) { - message = "recv failed, errno=" + std::to_string(errno); + message = "recv failed, " + lastErrorMessage(); } else { assert(transferred <= static_cast(size)); return transferred; @@ -152,7 +153,7 @@ size_t TcpConnection::write(const uint8_t* data, size_t size) { std::string message; if (size == 0) { if (shutdown(connection, SHUT_WR) == -1) { - throw std::runtime_error("TcpConnection::write, shutdown failed, result=" + std::to_string(errno)); + throw std::runtime_error("TcpConnection::write, shutdown failed, " + lastErrorMessage()); } return 0; @@ -161,7 +162,7 @@ size_t TcpConnection::write(const uint8_t* data, size_t size) { ssize_t transferred = ::send(connection, (void *)data, size, 0); if (transferred == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { - message = "send failed, result=" + std::to_string(errno); + message = "send failed, " + lastErrorMessage(); } else { OperationContext context; context.context = dispatcher->getCurrentContext(); @@ -169,7 +170,7 @@ size_t TcpConnection::write(const uint8_t* data, size_t size) { struct kevent event; EV_SET(&event, connection, EVFILT_WRITE, EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 0, &context); if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) { - message = "kevent() failed, errno=" + std::to_string(errno); + message = "kevent failed, " + lastErrorMessage(); } else { writeContext = &context; dispatcher->getCurrentContext()->interruptProcedure = [&] { @@ -181,7 +182,7 @@ size_t TcpConnection::write(const uint8_t* data, size_t size) { EV_SET(&event, connection, EVFILT_WRITE, EV_DELETE | EV_DISABLE, 0, 0, NULL); if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) { - throw std::runtime_error("TcpListener::stop, kevent() failed, errno=" + std::to_string(errno)); + throw std::runtime_error("TcpListener::stop, kevent failed, " + lastErrorMessage()); } context->interrupted = true; @@ -202,7 +203,7 @@ size_t TcpConnection::write(const uint8_t* data, size_t size) { ssize_t transferred = ::send(connection, (void *)data, size, 0); if (transferred == -1) { - message = "send failed, errno=" + std::to_string(errno); + message = "send failed, " + lastErrorMessage(); } else { assert(transferred <= static_cast(size)); return transferred; @@ -221,7 +222,7 @@ std::pair TcpConnection::getPeerAddressAndPort() const { sockaddr_in addr; socklen_t size = sizeof(addr); if (getpeername(connection, reinterpret_cast(&addr), &size) != 0) { - throw std::runtime_error("TcpConnection::getPeerAddress, getpeername failed, result=" + std::to_string(errno)); + throw std::runtime_error("TcpConnection::getPeerAddress, getpeername failed, " + lastErrorMessage()); } assert(size == sizeof(sockaddr_in)); @@ -231,7 +232,7 @@ std::pair TcpConnection::getPeerAddressAndPort() const { TcpConnection::TcpConnection(Dispatcher& dispatcher, int socket) : dispatcher(&dispatcher), connection(socket), readContext(nullptr), writeContext(nullptr) { int val = 1; if (setsockopt(connection, SOL_SOCKET, SO_NOSIGPIPE, (void*)&val, sizeof val) == -1) { - throw std::runtime_error("TcpConnection::TcpConnection, setsockopt failed, result=" + std::to_string(errno)); + throw std::runtime_error("TcpConnection::TcpConnection, setsockopt failed, " + lastErrorMessage()); } } diff --git a/src/Platform/OSX/System/TcpConnector.cpp b/src/Platform/OSX/System/TcpConnector.cpp index 898b9536..6a5d07f1 100755 --- a/src/Platform/OSX/System/TcpConnector.cpp +++ b/src/Platform/OSX/System/TcpConnector.cpp @@ -29,6 +29,7 @@ #include #include #include "Dispatcher.h" +#include "ErrorMessage.h" #include "TcpConnection.h" namespace System { @@ -80,18 +81,18 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) { std::string message; int connection = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (connection == -1) { - message = "socket() failed, errno=" + std::to_string(errno); + message = "socket failed, " + lastErrorMessage(); } else { sockaddr_in bindAddress; bindAddress.sin_family = AF_INET; bindAddress.sin_port = 0; bindAddress.sin_addr.s_addr = INADDR_ANY; if (bind(connection, reinterpret_cast(&bindAddress), sizeof bindAddress) != 0) { - message = "bind failed, errno=" + std::to_string(errno); + message = "bind failed, " + lastErrorMessage(); } else { int flags = fcntl(connection, F_GETFL, 0); if (flags == -1 || fcntl(connection, F_SETFL, flags | O_NONBLOCK) == -1) { - message = "fcntl() failed errno=" + std::to_string(errno); + message = "fcntl failed, " + lastErrorMessage(); } else { sockaddr_in addressData; addressData.sin_family = AF_INET; @@ -108,7 +109,7 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) { struct kevent event; EV_SET(&event, connection, EVFILT_WRITE, EV_ADD | EV_ENABLE | EV_ONESHOT | EV_CLEAR, 0, 0, &connectorContext); if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) { - message = "kevent() failed, errno=" + std::to_string(errno); + message = "kevent failed, " + lastErrorMessage(); } else { context = &connectorContext; dispatcher->getCurrentContext()->interruptProcedure = [&] { @@ -117,7 +118,7 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) { ConnectorContext* connectorContext = static_cast(context); if (!connectorContext->interrupted) { if (close(connectorContext->connection) == -1) { - throw std::runtime_error("TcpListener::stop, close failed, errno=" + std::to_string(errno)); + throw std::runtime_error("TcpListener::stop, close failed, " + lastErrorMessage()); } dispatcher->pushContext(connectorContext->context); @@ -140,16 +141,16 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) { EV_SET(&event, connection, EVFILT_WRITE, EV_ADD | EV_DISABLE, 0, 0, NULL); if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) { - message = "kevent() failed, errno=" + std::to_string(errno); + message = "kevent failed, " + lastErrorMessage(); } else { int retval = -1; socklen_t retValLen = sizeof(retval); int s = getsockopt(connection, SOL_SOCKET, SO_ERROR, &retval, &retValLen); if (s == -1) { - message = "getsockopt() failed, errno=" + std::to_string(errno); + message = "getsockopt failed, " + lastErrorMessage(); } else { if (retval != 0) { - message = "connect failed; getsockopt retval =" + std::to_string(errno); + message = "getsockopt failed, " + lastErrorMessage(); } else { return TcpConnection(*dispatcher, connection); } diff --git a/src/Platform/OSX/System/TcpListener.cpp b/src/Platform/OSX/System/TcpListener.cpp index 7c9ea2d3..907c1e61 100755 --- a/src/Platform/OSX/System/TcpListener.cpp +++ b/src/Platform/OSX/System/TcpListener.cpp @@ -29,6 +29,7 @@ #include "Dispatcher.h" #include "TcpConnection.h" +#include #include #include @@ -41,30 +42,30 @@ TcpListener::TcpListener(Dispatcher& dispatcher, const Ipv4Address& addr, uint16 std::string message; listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (listener == -1) { - message = "socket() failed, errno=" + std::to_string(errno); + message = "socket failed, " + lastErrorMessage(); } else { int flags = fcntl(listener, F_GETFL, 0); if (flags == -1 || (fcntl(listener, F_SETFL, flags | O_NONBLOCK) == -1)) { - message = "fcntl() failed errno=" + std::to_string(errno); + message = "fcntl failed, " + lastErrorMessage(); } else { int on = 1; if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on) == -1) { - message = "setsockopt failed, errno=" + std::to_string(errno); + message = "setsockopt failed, " + lastErrorMessage(); } else { sockaddr_in address; address.sin_family = AF_INET; address.sin_port = htons(port); address.sin_addr.s_addr = htonl(addr.getValue()); if (bind(listener, reinterpret_cast(&address), sizeof address) != 0) { - message = "bind failed, errno=" + std::to_string(errno); + message = "bind failed, " + lastErrorMessage(); } else if (listen(listener, SOMAXCONN) != 0) { - message = "listen failed, errno=" + std::to_string(errno); + message = "listen failed, " + lastErrorMessage(); } else { struct kevent event; EV_SET(&event, listener, EVFILT_READ, EV_ADD | EV_DISABLE | EV_CLEAR, 0, SOMAXCONN, NULL); if (kevent(dispatcher.getKqueue(), &event, 1, NULL, 0, NULL) == -1) { - message = "kevent() failed, errno=" + std::to_string(errno); + message = "kevent failed, " + lastErrorMessage(); } else { context = nullptr; return; @@ -74,7 +75,7 @@ TcpListener::TcpListener(Dispatcher& dispatcher, const Ipv4Address& addr, uint16 } if (close(listener) == -1) { - message = "close failed, errno=" + std::to_string(errno); + message = "close failed, " + lastErrorMessage(); } } @@ -102,7 +103,7 @@ TcpListener& TcpListener::operator=(TcpListener&& other) { if (dispatcher != nullptr) { assert(context == nullptr); if (close(listener) == -1) { - throw std::runtime_error("TcpListener::operator=, close failed, errno=" + std::to_string(errno)); + throw std::runtime_error("TcpListener::operator=, close failed, " + lastErrorMessage()); } } @@ -131,7 +132,7 @@ TcpConnection TcpListener::accept() { struct kevent event; EV_SET(&event, listener, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR , 0, SOMAXCONN, &listenerContext); if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) { - message = "kevent() failed, errno=" + std::to_string(errno); + message = "kevent failed, " + lastErrorMessage(); } else { context = &listenerContext; dispatcher->getCurrentContext()->interruptProcedure = [&] { @@ -144,7 +145,7 @@ TcpConnection TcpListener::accept() { EV_SET(&event, listener, EVFILT_READ, EV_DELETE | EV_DISABLE, 0, 0, NULL); if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) { - throw std::runtime_error("TcpListener::stop, kevent() failed, errno=" + std::to_string(errno)); + throw std::runtime_error("TcpListener::stop, kevent failed, " + lastErrorMessage()); } listenerContext->interrupted = true; @@ -167,11 +168,11 @@ TcpConnection TcpListener::accept() { socklen_t inLen = sizeof(inAddr); int connection = ::accept(listener, &inAddr, &inLen); if (connection == -1) { - message = "accept() failed, errno=" + std::to_string(errno); + message = "accept failed, " + lastErrorMessage(); } else { int flags = fcntl(connection, F_GETFL, 0); if (flags == -1 || fcntl(connection, F_SETFL, flags | O_NONBLOCK) == -1) { - message = "fcntl() failed errno=" + std::to_string(errno); + message = "fcntl failed, " + lastErrorMessage(); } else { return TcpConnection(*dispatcher, connection); } diff --git a/src/Platform/OSX/System/Timer.cpp b/src/Platform/OSX/System/Timer.cpp index 6f61c7b5..254d683f 100755 --- a/src/Platform/OSX/System/Timer.cpp +++ b/src/Platform/OSX/System/Timer.cpp @@ -26,6 +26,7 @@ #include #include "Dispatcher.h" +#include #include namespace System { @@ -79,7 +80,7 @@ void Timer::sleep(std::chrono::nanoseconds duration) { EV_SET(&event, timer, EVFILT_TIMER, EV_ADD | EV_ENABLE | EV_ONESHOT, NOTE_NSECONDS, duration.count(), &timerContext); if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) { - throw std::runtime_error("Timer::stop, kevent() failed, errno=" + std::to_string(errno)); + throw std::runtime_error("Timer::stop, kevent failed, " + lastErrorMessage()); } context = &timerContext; @@ -92,7 +93,7 @@ void Timer::sleep(std::chrono::nanoseconds duration) { EV_SET(&event, timer, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); if (kevent(dispatcher->getKqueue(), &event, 1, NULL, 0, NULL) == -1) { - throw std::runtime_error("Timer::stop, kevent() failed, errno=" + std::to_string(errno)); + throw std::runtime_error("Timer::stop, kevent failed, " + lastErrorMessage()); } dispatcher->pushContext(timerContext->context); diff --git a/src/Platform/Windows/System/Dispatcher.cpp b/src/Platform/Windows/System/Dispatcher.cpp index 2fd59441..22d67e57 100755 --- a/src/Platform/Windows/System/Dispatcher.cpp +++ b/src/Platform/Windows/System/Dispatcher.cpp @@ -25,6 +25,7 @@ #define NOMINMAX #endif #include +#include "ErrorMessage.h" namespace System { @@ -44,16 +45,16 @@ Dispatcher::Dispatcher() { assert(result != FALSE); std::string message; if (ConvertThreadToFiberEx(NULL, 0) == NULL) { - message = "ConvertThreadToFiberEx failed, result=" + std::to_string(GetLastError()); + message = "ConvertThreadToFiberEx failed, " + lastErrorMessage(); } else { completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); if (completionPort == NULL) { - message = "CreateIoCompletionPort failed, result=" + std::to_string(GetLastError()); + message = "CreateIoCompletionPort failed, " + lastErrorMessage(); } else { WSADATA wsaData; int wsaResult = WSAStartup(0x0202, &wsaData); if (wsaResult != 0) { - message = "WSAStartup failed, result=" + std::to_string(wsaResult); + message = "WSAStartup failed, " + errorMessage(wsaResult); } else { remoteNotificationSent = false; reinterpret_cast(remoteSpawnOverlapped)->hEvent = NULL; @@ -179,7 +180,7 @@ void Dispatcher::dispatch() { } if (lastError != WAIT_IO_COMPLETION) { - throw std::runtime_error("Dispatcher::dispatch, GetQueuedCompletionStatusEx failed, result=" + std::to_string(lastError)); + throw std::runtime_error("Dispatcher::dispatch, GetQueuedCompletionStatusEx failed, " + errorMessage(lastError)); } } @@ -241,7 +242,7 @@ void Dispatcher::remoteSpawn(std::function&& procedure) { remoteNotificationSent = true; if (PostQueuedCompletionStatus(completionPort, 0, 0, reinterpret_cast(remoteSpawnOverlapped)) == NULL) { LeaveCriticalSection(reinterpret_cast(criticalSection)); - throw std::runtime_error("Dispatcher::remoteSpawn, PostQueuedCompletionStatus failed, result=" + std::to_string(GetLastError())); + throw std::runtime_error("Dispatcher::remoteSpawn, PostQueuedCompletionStatus failed, " + lastErrorMessage()); }; } @@ -313,7 +314,7 @@ void Dispatcher::yield() { if (lastError == WAIT_TIMEOUT) { break; } else if (lastError != WAIT_IO_COMPLETION) { - throw std::runtime_error("Dispatcher::yield, GetQueuedCompletionStatusEx failed, result=" + std::to_string(lastError)); + throw std::runtime_error("Dispatcher::yield, GetQueuedCompletionStatusEx failed, " + errorMessage(lastError)); } } } @@ -337,7 +338,7 @@ NativeContext& Dispatcher::getReusableContext() { if (firstReusableContext == nullptr) { void* fiber = CreateFiberEx(STACK_SIZE, RESERVE_STACK_SIZE, 0, contextProcedureStatic, this); if (fiber == NULL) { - throw std::runtime_error("Dispatcher::getReusableContext, CreateFiberEx failed, result=" + std::to_string(GetLastError())); + throw std::runtime_error("Dispatcher::getReusableContext, CreateFiberEx failed, " + lastErrorMessage()); } SwitchToFiber(fiber); diff --git a/src/Platform/Windows/System/ErrorMessage.cpp b/src/Platform/Windows/System/ErrorMessage.cpp new file mode 100644 index 00000000..8773b29e --- /dev/null +++ b/src/Platform/Windows/System/ErrorMessage.cpp @@ -0,0 +1,45 @@ +// Copyright (c) 2012-2015, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#include "ErrorMessage.h" + +#include +#include + +namespace System { + +std::string lastErrorMessage() { + return errorMessage(GetLastError()); +} + +std::string errorMessage(int error) { + struct Buffer { + ~Buffer() { + if (pointer != nullptr) { + LocalFree(pointer); + } + } + + LPTSTR pointer = nullptr; + } buffer; + + auto size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, nullptr, error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast(&buffer.pointer), 0, nullptr); + return "result=" + std::to_string(error) + ", " + std::string(buffer.pointer, size); +} + +} diff --git a/src/Platform/Windows/System/ErrorMessage.h b/src/Platform/Windows/System/ErrorMessage.h new file mode 100644 index 00000000..e48a708c --- /dev/null +++ b/src/Platform/Windows/System/ErrorMessage.h @@ -0,0 +1,27 @@ +// Copyright (c) 2012-2015, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#pragma once + +#include + +namespace System { + +std::string lastErrorMessage(); +std::string errorMessage(int); + +} diff --git a/src/Platform/Windows/System/Ipv4Resolver.cpp b/src/Platform/Windows/System/Ipv4Resolver.cpp index 64f03e7a..2bd7b5ab 100755 --- a/src/Platform/Windows/System/Ipv4Resolver.cpp +++ b/src/Platform/Windows/System/Ipv4Resolver.cpp @@ -23,6 +23,7 @@ #endif #include #include +#include #include #include @@ -62,7 +63,7 @@ Ipv4Address Ipv4Resolver::resolve(const std::string& host) { addrinfo* addressInfos; int result = getaddrinfo(host.c_str(), NULL, &hints, &addressInfos); if (result != 0) { - throw std::runtime_error("Ipv4Resolver::resolve, getaddrinfo failed, result=" + std::to_string(result)); + throw std::runtime_error("Ipv4Resolver::resolve, getaddrinfo failed, " + errorMessage(result)); } size_t count = 0; diff --git a/src/Platform/Windows/System/TcpConnection.cpp b/src/Platform/Windows/System/TcpConnection.cpp index 4a8ee621..a038a924 100755 --- a/src/Platform/Windows/System/TcpConnection.cpp +++ b/src/Platform/Windows/System/TcpConnection.cpp @@ -25,6 +25,7 @@ #include #include #include "Dispatcher.h" +#include "ErrorMessage.h" namespace System { @@ -65,7 +66,7 @@ TcpConnection& TcpConnection::operator=(TcpConnection&& other) { assert(readContext == nullptr); assert(writeContext == nullptr); if (closesocket(connection) != 0) { - throw std::runtime_error("TcpConnection::operator=, closesocket failed, result=" + std::to_string(WSAGetLastError())); + throw std::runtime_error("TcpConnection::operator=, closesocket failed, " + errorMessage(WSAGetLastError())); } } @@ -96,7 +97,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) { if (WSARecv(connection, &buf, 1, NULL, &flags, &context, NULL) != 0) { int lastError = WSAGetLastError(); if (lastError != WSA_IO_PENDING) { - throw std::runtime_error("TcpConnection::read, WSARecv failed, result=" + std::to_string(lastError)); + throw std::runtime_error("TcpConnection::read, WSARecv failed, " + errorMessage(lastError)); } } @@ -112,7 +113,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) { if (CancelIoEx(reinterpret_cast(connection), context) != TRUE) { DWORD lastError = GetLastError(); if (lastError != ERROR_NOT_FOUND) { - throw std::runtime_error("TcpConnection::stop, CancelIoEx failed, result=" + std::to_string(GetLastError())); + throw std::runtime_error("TcpConnection::stop, CancelIoEx failed, " + lastErrorMessage()); } context->context->interrupted = true; @@ -132,7 +133,7 @@ size_t TcpConnection::read(uint8_t* data, size_t size) { if (WSAGetOverlappedResult(connection, &context, &transferred, FALSE, &flags) != TRUE) { int lastError = WSAGetLastError(); if (lastError != ERROR_OPERATION_ABORTED) { - throw std::runtime_error("TcpConnection::read, WSAGetOverlappedResult failed, result=" + std::to_string(lastError)); + throw std::runtime_error("TcpConnection::read, WSAGetOverlappedResult failed, " + errorMessage(lastError)); } assert(context.interrupted); @@ -153,7 +154,7 @@ size_t TcpConnection::write(const uint8_t* data, size_t size) { if (size == 0) { if (shutdown(connection, SD_SEND) != 0) { - throw std::runtime_error("TcpConnection::write, shutdown failed, result=" + std::to_string(WSAGetLastError())); + throw std::runtime_error("TcpConnection::write, shutdown failed, " + errorMessage(WSAGetLastError())); } return 0; @@ -165,7 +166,7 @@ size_t TcpConnection::write(const uint8_t* data, size_t size) { if (WSASend(connection, &buf, 1, NULL, 0, &context, NULL) != 0) { int lastError = WSAGetLastError(); if (lastError != WSA_IO_PENDING) { - throw std::runtime_error("TcpConnection::write, WSASend failed, result=" + std::to_string(lastError)); + throw std::runtime_error("TcpConnection::write, WSASend failed, " + errorMessage(lastError)); } } @@ -180,7 +181,7 @@ size_t TcpConnection::write(const uint8_t* data, size_t size) { if (CancelIoEx(reinterpret_cast(connection), context) != TRUE) { DWORD lastError = GetLastError(); if (lastError != ERROR_NOT_FOUND) { - throw std::runtime_error("TcpConnection::stop, CancelIoEx failed, result=" + std::to_string(GetLastError())); + throw std::runtime_error("TcpConnection::stop, CancelIoEx failed, " + lastErrorMessage()); } context->context->interrupted = true; @@ -201,7 +202,7 @@ size_t TcpConnection::write(const uint8_t* data, size_t size) { if (WSAGetOverlappedResult(connection, &context, &transferred, FALSE, &flags) != TRUE) { int lastError = WSAGetLastError(); if (lastError != ERROR_OPERATION_ABORTED) { - throw std::runtime_error("TcpConnection::write, WSAGetOverlappedResult failed, result=" + std::to_string(lastError)); + throw std::runtime_error("TcpConnection::write, WSAGetOverlappedResult failed, " + errorMessage(lastError)); } assert(context.interrupted); @@ -217,7 +218,7 @@ std::pair TcpConnection::getPeerAddressAndPort() const { sockaddr_in address; int size = sizeof(address); if (getpeername(connection, reinterpret_cast(&address), &size) != 0) { - throw std::runtime_error("TcpConnection::getPeerAddress, getpeername failed, result=" + std::to_string(WSAGetLastError())); + throw std::runtime_error("TcpConnection::getPeerAddress, getpeername failed, " + errorMessage(WSAGetLastError())); } assert(size == sizeof(sockaddr_in)); diff --git a/src/Platform/Windows/System/TcpConnector.cpp b/src/Platform/Windows/System/TcpConnector.cpp index 5a19ac44..2d85f9c8 100755 --- a/src/Platform/Windows/System/TcpConnector.cpp +++ b/src/Platform/Windows/System/TcpConnector.cpp @@ -25,6 +25,7 @@ #include #include #include "Dispatcher.h" +#include "ErrorMessage.h" #include "TcpConnection.h" namespace System { @@ -81,23 +82,23 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) { std::string message; SOCKET connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (connection == INVALID_SOCKET) { - message = "socket failed, result=" + std::to_string(WSAGetLastError()); + message = "socket failed, " + errorMessage(WSAGetLastError()); } else { sockaddr_in bindAddress; bindAddress.sin_family = AF_INET; bindAddress.sin_port = 0; bindAddress.sin_addr.s_addr = INADDR_ANY; if (bind(connection, reinterpret_cast(&bindAddress), sizeof bindAddress) != 0) { - message = "bind failed, result=" + std::to_string(WSAGetLastError()); + message = "bind failed, " + errorMessage(WSAGetLastError()); } else { GUID guidConnectEx = WSAID_CONNECTEX; DWORD read = sizeof connectEx; if (connectEx == nullptr && WSAIoctl(connection, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidConnectEx, sizeof guidConnectEx, &connectEx, sizeof connectEx, &read, NULL, NULL) != 0) { - message = "WSAIoctl failed, result=" + std::to_string(WSAGetLastError()); + message = "WSAIoctl failed, " + errorMessage(WSAGetLastError()); } else { assert(read == sizeof connectEx); if (CreateIoCompletionPort(reinterpret_cast(connection), dispatcher->getCompletionPort(), 0, 0) != dispatcher->getCompletionPort()) { - message = "CreateIoCompletionPort failed, result=" + std::to_string(GetLastError()); + message = "CreateIoCompletionPort failed, " + lastErrorMessage(); } else { sockaddr_in addressData; addressData.sin_family = AF_INET; @@ -110,7 +111,7 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) { } else { int lastError = WSAGetLastError(); if (lastError != WSA_IO_PENDING) { - message = "ConnectEx failed, result=" + std::to_string(lastError); + message = "ConnectEx failed, " + errorMessage(lastError); } else { context2.context = dispatcher->getCurrentContext(); context2.connection = connection; @@ -124,7 +125,7 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) { if (CancelIoEx(reinterpret_cast(context2->connection), context2) != TRUE) { DWORD lastError = GetLastError(); if (lastError != ERROR_NOT_FOUND) { - throw std::runtime_error("TcpConnector::stop, CancelIoEx failed, result=" + std::to_string(GetLastError())); + throw std::runtime_error("TcpConnector::stop, CancelIoEx failed, " + lastErrorMessage()); } context2->context->interrupted = true; @@ -146,11 +147,11 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) { if (WSAGetOverlappedResult(connection, &context2, &transferred, FALSE, &flags) != TRUE) { lastError = WSAGetLastError(); if (lastError != ERROR_OPERATION_ABORTED) { - message = "ConnectEx failed, result=" + std::to_string(lastError); + message = "ConnectEx failed, " + errorMessage(lastError); } else { assert(context2.interrupted); if (closesocket(connection) != 0) { - throw std::runtime_error("TcpConnector::connect, closesocket failed, result=" + std::to_string(WSAGetLastError())); + throw std::runtime_error("TcpConnector::connect, closesocket failed, " + errorMessage(WSAGetLastError())); } else { throw InterruptedException(); } @@ -160,7 +161,7 @@ TcpConnection TcpConnector::connect(const Ipv4Address& address, uint16_t port) { assert(flags == 0); DWORD value = 1; if (setsockopt(connection, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, reinterpret_cast(&value), sizeof(value)) != 0) { - message = "setsockopt failed, result=" + std::to_string(WSAGetLastError()); + message = "setsockopt failed, " + errorMessage(WSAGetLastError()); } else { return TcpConnection(*dispatcher, connection); } diff --git a/src/Platform/Windows/System/TcpListener.cpp b/src/Platform/Windows/System/TcpListener.cpp index 3c546a59..8528f8d2 100755 --- a/src/Platform/Windows/System/TcpListener.cpp +++ b/src/Platform/Windows/System/TcpListener.cpp @@ -25,6 +25,7 @@ #include #include #include "Dispatcher.h" +#include "ErrorMessage.h" #include "TcpConnection.h" namespace System { @@ -47,25 +48,25 @@ TcpListener::TcpListener(Dispatcher& dispatcher, const Ipv4Address& address, uin std::string message; listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (listener == INVALID_SOCKET) { - message = "socket failed, result=" + std::to_string(WSAGetLastError()); + message = "socket failed, " + errorMessage(WSAGetLastError()); } else { sockaddr_in addressData; addressData.sin_family = AF_INET; addressData.sin_port = htons(port); addressData.sin_addr.S_un.S_addr = htonl(address.getValue()); if (bind(listener, reinterpret_cast(&addressData), sizeof(addressData)) != 0) { - message = "bind failed, result=" + std::to_string(WSAGetLastError()); + message = "bind failed, " + errorMessage(WSAGetLastError()); } else if (listen(listener, SOMAXCONN) != 0) { - message = "listen failed, result=" + std::to_string(WSAGetLastError()); + message = "listen failed, " + errorMessage(WSAGetLastError()); } else { GUID guidAcceptEx = WSAID_ACCEPTEX; DWORD read = sizeof acceptEx; if (acceptEx == nullptr && WSAIoctl(listener, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidAcceptEx, sizeof guidAcceptEx, &acceptEx, sizeof acceptEx, &read, NULL, NULL) != 0) { - message = "WSAIoctl failed, result=" + std::to_string(WSAGetLastError()); + message = "WSAIoctl failed, " + errorMessage(WSAGetLastError()); } else { assert(read == sizeof acceptEx); if (CreateIoCompletionPort(reinterpret_cast(listener), dispatcher.getCompletionPort(), 0, 0) != dispatcher.getCompletionPort()) { - message = "CreateIoCompletionPort failed, result=" + std::to_string(GetLastError()); + message = "CreateIoCompletionPort failed, " + lastErrorMessage(); } else { context = nullptr; return; @@ -101,7 +102,7 @@ TcpListener& TcpListener::operator=(TcpListener&& other) { if (dispatcher != nullptr) { assert(context == nullptr); if (closesocket(listener) != 0) { - throw std::runtime_error("TcpListener::operator=, closesocket failed, result=" + std::to_string(WSAGetLastError())); + throw std::runtime_error("TcpListener::operator=, closesocket failed, " + errorMessage(WSAGetLastError())); } } @@ -126,7 +127,7 @@ TcpConnection TcpListener::accept() { std::string message; SOCKET connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (connection == INVALID_SOCKET) { - message = "socket failed, result=" + std::to_string(WSAGetLastError()); + message = "socket failed, " + errorMessage(WSAGetLastError()); } else { uint8_t addresses[sizeof sockaddr_in * 2 + 32]; DWORD received; @@ -137,7 +138,7 @@ TcpConnection TcpListener::accept() { } else { int lastError = WSAGetLastError(); if (lastError != WSA_IO_PENDING) { - message = "AcceptEx failed, result=" + std::to_string(lastError); + message = "AcceptEx failed, " + errorMessage(lastError); } else { context2.context = dispatcher->getCurrentContext(); context2.interrupted = false; @@ -150,7 +151,7 @@ TcpConnection TcpListener::accept() { if (CancelIoEx(reinterpret_cast(listener), context2) != TRUE) { DWORD lastError = GetLastError(); if (lastError != ERROR_NOT_FOUND) { - throw std::runtime_error("TcpListener::stop, CancelIoEx failed, result=" + std::to_string(GetLastError())); + throw std::runtime_error("TcpListener::stop, CancelIoEx failed, " + lastErrorMessage()); } context2->context->interrupted = true; @@ -171,11 +172,11 @@ TcpConnection TcpListener::accept() { if (WSAGetOverlappedResult(listener, &context2, &transferred, FALSE, &flags) != TRUE) { lastError = WSAGetLastError(); if (lastError != ERROR_OPERATION_ABORTED) { - message = "AcceptEx failed, result=" + std::to_string(lastError); + message = "AcceptEx failed, " + errorMessage(lastError); } else { assert(context2.interrupted); if (closesocket(connection) != 0) { - throw std::runtime_error("TcpListener::accept, closesocket failed, result=" + std::to_string(WSAGetLastError())); + throw std::runtime_error("TcpListener::accept, closesocket failed, " + errorMessage(WSAGetLastError())); } else { throw InterruptedException(); } @@ -184,10 +185,10 @@ TcpConnection TcpListener::accept() { assert(transferred == 0); assert(flags == 0); if (setsockopt(connection, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, reinterpret_cast(&listener), sizeof listener) != 0) { - message = "setsockopt failed, result=" + std::to_string(WSAGetLastError()); + message = "setsockopt failed, " + errorMessage(WSAGetLastError()); } else { if (CreateIoCompletionPort(reinterpret_cast(connection), dispatcher->getCompletionPort(), 0, 0) != dispatcher->getCompletionPort()) { - message = "CreateIoCompletionPort failed, result=" + std::to_string(GetLastError()); + message = "CreateIoCompletionPort failed, " + lastErrorMessage(); } else { return TcpConnection(*dispatcher, connection); } diff --git a/src/Serialization/SerializationOverloads.cpp b/src/Serialization/SerializationOverloads.cpp new file mode 100644 index 00000000..55a23830 --- /dev/null +++ b/src/Serialization/SerializationOverloads.cpp @@ -0,0 +1,45 @@ +// Copyright (c) 2012-2015, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#include "Serialization/SerializationOverloads.h" + +#include + +namespace CryptoNote { + +void serializeBlockHeight(ISerializer& s, uint32_t& blockHeight, Common::StringView name) { + if (s.type() == ISerializer::INPUT) { + uint64_t height; + s(height, name); + + if (height == std::numeric_limits::max()) { + blockHeight = std::numeric_limits::max(); + } else if (height > std::numeric_limits::max() && height < std::numeric_limits::max()) { + throw std::runtime_error("Deserialization error: wrong value"); + } else { + blockHeight = static_cast(height); + } + } else { + s(blockHeight, name); + } +} + +void serializeGlobalOutputIndex(ISerializer& s, uint32_t& globalOutputIndex, Common::StringView name) { + serializeBlockHeight(s, globalOutputIndex, name); +} + +} //namespace CryptoNote diff --git a/src/Serialization/SerializationOverloads.h b/src/Serialization/SerializationOverloads.h index 4b115d0f..d535c17a 100644 --- a/src/Serialization/SerializationOverloads.h +++ b/src/Serialization/SerializationOverloads.h @@ -249,4 +249,10 @@ void readSequence(Iterator outputIterator, Common::StringView name, ISerializer& s.endArray(); } +//convinience function since we change block height type +void serializeBlockHeight(ISerializer& s, uint32_t& blockHeight, Common::StringView name); + +//convinience function since we change global output index type +void serializeGlobalOutputIndex(ISerializer& s, uint32_t& globalOutputIndex, Common::StringView name); + } diff --git a/src/Transfers/TransfersContainer.cpp b/src/Transfers/TransfersContainer.cpp index 39dba73f..6823ea1f 100755 --- a/src/Transfers/TransfersContainer.cpp +++ b/src/Transfers/TransfersContainer.cpp @@ -22,6 +22,7 @@ #include "CryptoNoteCore/CryptoNoteFormatUtils.h" #include "Serialization/BinaryInputStreamSerializer.h" #include "Serialization/BinaryOutputStreamSerializer.h" +#include "Serialization/SerializationOverloads.h" using namespace Common; using namespace Crypto; @@ -31,7 +32,7 @@ namespace CryptoNote { void serialize(TransactionInformation& ti, CryptoNote::ISerializer& s) { s(ti.transactionHash, ""); s(ti.publicKey, ""); - s(ti.blockHeight, ""); + serializeBlockHeight(s, ti.blockHeight, ""); s(ti.timestamp, ""); s(ti.unlockTime, ""); s(ti.totalAmountIn, ""); diff --git a/src/Transfers/TransfersContainer.h b/src/Transfers/TransfersContainer.h index 003208de..1f08b144 100755 --- a/src/Transfers/TransfersContainer.h +++ b/src/Transfers/TransfersContainer.h @@ -89,12 +89,12 @@ struct TransactionOutputInformationEx : public TransactionOutputInformationIn { void serialize(CryptoNote::ISerializer& s) { s(reinterpret_cast(type), "type"); s(amount, ""); - s(globalOutputIndex, ""); + serializeGlobalOutputIndex(s, globalOutputIndex, ""); s(outputInTransaction, ""); s(transactionPublicKey, ""); s(keyImage, ""); s(unlockTime, ""); - s(blockHeight, ""); + serializeBlockHeight(s, blockHeight, ""); s(transactionIndex, ""); s(transactionHash, ""); s(visible, ""); @@ -113,7 +113,7 @@ struct BlockInfo { uint32_t transactionIndex; void serialize(ISerializer& s) { - s(height, "height"); + serializeBlockHeight(s, height, "height"); s(timestamp, "timestamp"); s(transactionIndex, "transactionIndex"); } diff --git a/src/Wallet/WalletSerialization.cpp b/src/Wallet/WalletSerialization.cpp index d68adff1..f50bfe55 100755 --- a/src/Wallet/WalletSerialization.cpp +++ b/src/Wallet/WalletSerialization.cpp @@ -144,7 +144,7 @@ void serialize(WalletTransactionDto& value, CryptoNote::ISerializer& serializer) value.state = static_cast(state); serializer(value.timestamp, "timestamp"); - serializer(value.blockHeight, "block_height"); + CryptoNote::serializeBlockHeight(serializer, value.blockHeight, "block_height"); serializer(value.hash, "hash"); serializer(value.totalAmount, "total_amount"); serializer(value.fee, "fee"); diff --git a/src/WalletLegacy/WalletLegacy.cpp b/src/WalletLegacy/WalletLegacy.cpp index 664a8309..39033b5f 100755 --- a/src/WalletLegacy/WalletLegacy.cpp +++ b/src/WalletLegacy/WalletLegacy.cpp @@ -113,6 +113,7 @@ WalletLegacy::WalletLegacy(const CryptoNote::Currency& currency, INode& node) : m_blockchainSync(node, currency.genesisBlockHash()), m_transfersSync(currency, m_blockchainSync, node), m_transferDetails(nullptr), + m_transactionsCache(m_currency.mempoolTxLiveTime()), m_sender(nullptr), m_onInitSyncStarter(new SyncStarter(m_blockchainSync)) { @@ -501,9 +502,15 @@ std::error_code WalletLegacy::cancelTransaction(size_t transactionId) { } void WalletLegacy::synchronizationProgressUpdated(uint32_t current, uint32_t total) { + auto deletedTransactions = deleteOutdatedUnconfirmedTransactions(); + // forward notification m_observerManager.notify(&IWalletLegacyObserver::synchronizationProgressUpdated, current, total); + for (auto transactionId: deletedTransactions) { + m_observerManager.notify(&IWalletLegacyObserver::transactionUpdated, transactionId); + } + // check if balance has changed and notify client notifyIfBalanceChanged(); } @@ -513,9 +520,16 @@ void WalletLegacy::synchronizationCompleted(std::error_code result) { m_observerManager.notify(&IWalletLegacyObserver::synchronizationCompleted, result); } - if (!result) { - notifyIfBalanceChanged(); + if (result) { + return; } + + auto deletedTransactions = deleteOutdatedUnconfirmedTransactions(); + std::for_each(deletedTransactions.begin(), deletedTransactions.end(), [&] (TransactionId transactionId) { + m_observerManager.notify(&IWalletLegacyObserver::transactionUpdated, transactionId); + }); + + notifyIfBalanceChanged(); } void WalletLegacy::onTransactionUpdated(ITransfersSubscription* object, const Hash& transactionHash) { @@ -586,4 +600,9 @@ void WalletLegacy::getAccountKeys(AccountKeys& keys) { keys = m_account.getAccountKeys(); } +std::vector WalletLegacy::deleteOutdatedUnconfirmedTransactions() { + std::lock_guard lock(m_cacheMutex); + return m_transactionsCache.deleteOutdatedTransactions(); +} + } //namespace CryptoNote diff --git a/src/WalletLegacy/WalletLegacy.h b/src/WalletLegacy/WalletLegacy.h index 24fbd6b6..2ad7117d 100755 --- a/src/WalletLegacy/WalletLegacy.h +++ b/src/WalletLegacy/WalletLegacy.h @@ -106,6 +106,8 @@ private: void notifyClients(std::deque >& events); void notifyIfBalanceChanged(); + std::vector deleteOutdatedUnconfirmedTransactions(); + enum WalletState { NOT_INITIALIZED = 0, diff --git a/src/WalletLegacy/WalletLegacySerialization.cpp b/src/WalletLegacy/WalletLegacySerialization.cpp index 88166a4c..e6b6d076 100755 --- a/src/WalletLegacy/WalletLegacySerialization.cpp +++ b/src/WalletLegacy/WalletLegacySerialization.cpp @@ -52,18 +52,7 @@ void serialize(WalletLegacyTransaction& txi, CryptoNote::ISerializer& serializer serializer(txi.hash, "hash"); serializer(txi.isCoinbase, "is_coinbase"); - if (serializer.type() == ISerializer::INPUT) { - uint64_t height = 0; - serializer(height, "block_height"); - - if (height == std::numeric_limits::max()) { - txi.blockHeight = WALLET_LEGACY_UNCONFIRMED_TRANSACTION_HEIGHT; - } else { - txi.blockHeight = static_cast(height); - } - } else { - serializer(txi.blockHeight, "block_height"); - } + CryptoNote::serializeBlockHeight(serializer, txi.blockHeight, "block_height"); serializer(txi.timestamp, "timestamp"); serializer(txi.unlockTime, "unlock_time"); diff --git a/src/WalletLegacy/WalletUnconfirmedTransactions.cpp b/src/WalletLegacy/WalletUnconfirmedTransactions.cpp index ebd9a60a..18be8aa6 100755 --- a/src/WalletLegacy/WalletUnconfirmedTransactions.cpp +++ b/src/WalletLegacy/WalletUnconfirmedTransactions.cpp @@ -30,6 +30,11 @@ inline TransactionOutputId getOutputId(const TransactionOutputInformation& out) return std::make_pair(out.transactionPublicKey, out.outputInTransaction); } +WalletUnconfirmedTransactions::WalletUnconfirmedTransactions(uint64_t uncofirmedTransactionsLiveTime): + m_uncofirmedTransactionsLiveTime(uncofirmedTransactionsLiveTime) { + +} + bool WalletUnconfirmedTransactions::serialize(ISerializer& s) { s(m_unconfirmedTxs, "transactions"); if (s.type() == ISerializer::INPUT) { @@ -54,9 +59,7 @@ void WalletUnconfirmedTransactions::erase(const Hash& hash) { return; } - for (const auto& o : it->second.usedOutputs) { - m_usedOutputs.erase(o); - } + deleteUsedOutputs(it->second.usedOutputs); m_unconfirmedTxs.erase(it); } @@ -125,4 +128,29 @@ void WalletUnconfirmedTransactions::reset() { m_usedOutputs.clear(); } +void WalletUnconfirmedTransactions::deleteUsedOutputs(const std::vector& usedOutputs) { + for (const auto& output: usedOutputs) { + m_usedOutputs.erase(output); + } +} + +std::vector WalletUnconfirmedTransactions::deleteOutdatedTransactions() { + std::vector deletedTransactions; + + uint64_t now = static_cast(time(nullptr)); + assert(now >= m_uncofirmedTransactionsLiveTime); + + for (auto it = m_unconfirmedTxs.begin(); it != m_unconfirmedTxs.end();) { + if (static_cast(it->second.sentTime) <= now - m_uncofirmedTransactionsLiveTime) { + deleteUsedOutputs(it->second.usedOutputs); + deletedTransactions.push_back(it->second.transactionId); + it = m_unconfirmedTxs.erase(it); + } else { + ++it; + } + } + + return deletedTransactions; +} + } /* namespace CryptoNote */ diff --git a/src/WalletLegacy/WalletUnconfirmedTransactions.h b/src/WalletLegacy/WalletUnconfirmedTransactions.h index 9fbb2929..bbe21d68 100755 --- a/src/WalletLegacy/WalletUnconfirmedTransactions.h +++ b/src/WalletLegacy/WalletUnconfirmedTransactions.h @@ -65,6 +65,8 @@ class WalletUnconfirmedTransactions { public: + explicit WalletUnconfirmedTransactions(uint64_t uncofirmedTransactionsLiveTime); + bool serialize(CryptoNote::ISerializer& s); bool findTransactionId(const Crypto::Hash& hash, TransactionId& id); @@ -78,15 +80,19 @@ public: bool isUsed(const TransactionOutputInformation& out) const; void reset(); + std::vector deleteOutdatedTransactions(); + private: void collectUsedOutputs(); + void deleteUsedOutputs(const std::vector& usedOutputs); typedef std::unordered_map> UnconfirmedTxsContainer; typedef std::unordered_set UsedOutputsContainer; UnconfirmedTxsContainer m_unconfirmedTxs; UsedOutputsContainer m_usedOutputs; + uint64_t m_uncofirmedTransactionsLiveTime; }; } // namespace CryptoNote diff --git a/src/WalletLegacy/WalletUserTransactionsCache.cpp b/src/WalletLegacy/WalletUserTransactionsCache.cpp index 021e02f8..94200988 100755 --- a/src/WalletLegacy/WalletUserTransactionsCache.cpp +++ b/src/WalletLegacy/WalletUserTransactionsCache.cpp @@ -28,12 +28,18 @@ using namespace Crypto; namespace CryptoNote { + +WalletUserTransactionsCache::WalletUserTransactionsCache(uint64_t mempoolTxLiveTime) : m_unconfirmedTransactions(mempoolTxLiveTime) { +} + bool WalletUserTransactionsCache::serialize(CryptoNote::ISerializer& s) { if (s.type() == CryptoNote::ISerializer::INPUT) { s(m_transactions, "transactions"); s(m_transfers, "transfers"); s(m_unconfirmedTransactions, "unconfirmed"); + updateUnconfirmedTransactions(); + deleteOutdatedTransactions(); } else { UserTransactions txsToSave; UserTransfers transfersToSave; @@ -298,4 +304,15 @@ void WalletUserTransactionsCache::reset() { m_unconfirmedTransactions.reset(); } +std::vector WalletUserTransactionsCache::deleteOutdatedTransactions() { + auto deletedTransactions = m_unconfirmedTransactions.deleteOutdatedTransactions(); + + for (auto id: deletedTransactions) { + assert(id < m_transactions.size()); + m_transactions[id].state = WalletLegacyTransactionState::Deleted; + } + + return deletedTransactions; +} + } //namespace CryptoNote diff --git a/src/WalletLegacy/WalletUserTransactionsCache.h b/src/WalletLegacy/WalletUserTransactionsCache.h index 89754b7b..89b4add6 100755 --- a/src/WalletLegacy/WalletUserTransactionsCache.h +++ b/src/WalletLegacy/WalletUserTransactionsCache.h @@ -33,7 +33,7 @@ namespace CryptoNote { class WalletUserTransactionsCache { public: - WalletUserTransactionsCache() {} + explicit WalletUserTransactionsCache(uint64_t mempoolTxLiveTime = 60 * 60 * 24); bool serialize(CryptoNote::ISerializer& serializer); @@ -59,6 +59,8 @@ public: bool isUsed(const TransactionOutputInformation& out) const; void reset(); + std::vector deleteOutdatedTransactions(); + private: TransactionId findTransactionByHash(const Crypto::Hash& hash); diff --git a/src/version.h.in b/src/version.h.in index 98ee5155..88e14bd0 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -1,4 +1,4 @@ #define BUILD_COMMIT_ID "@VERSION@" -#define PROJECT_VERSION "1.0.6" -#define PROJECT_VERSION_BUILD_NO "542" +#define PROJECT_VERSION "1.0.6.1" +#define PROJECT_VERSION_BUILD_NO "550" #define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")" diff --git a/tests/CoreTests/BoostSerializationHelper.h b/tests/CoreTests/BoostSerializationHelper.h index 2f98b93a..6a8f38d7 100755 --- a/tests/CoreTests/BoostSerializationHelper.h +++ b/tests/CoreTests/BoostSerializationHelper.h @@ -17,90 +17,47 @@ #pragma once -#ifdef _WIN32 -#include -#ifndef NOMINMAX -#define NOMINMAX -#endif -#include -#endif - #include +#include +#include #include #include -namespace Tools -{ - template - bool serialize_obj_to_file(t_object& obj, const std::string& file_path) - { - try { -#ifdef _WIN32 - // Need to know HANDLE of file to call FlushFileBuffers - HANDLE data_file_handle = ::CreateFile(file_path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (INVALID_HANDLE_VALUE == data_file_handle) - return false; +namespace Tools { - int data_file_descriptor = _open_osfhandle((intptr_t)data_file_handle, 0); - if (-1 == data_file_descriptor) { - ::CloseHandle(data_file_handle); - return false; - } - - FILE* data_file_file = _fdopen(data_file_descriptor, "wb"); - if (0 == data_file_file) { - // Call CloseHandle is not necessary - _close(data_file_descriptor); - return false; - } - - // HACK: undocumented constructor, this code may not compile - std::ofstream data_file(data_file_file); - if (data_file.fail()) { - // Call CloseHandle and _close are not necessary - fclose(data_file_file); - return false; - } -#else - std::ofstream data_file; - data_file.open(file_path , std::ios_base::binary | std::ios_base::out| std::ios::trunc); - if (data_file.fail()) - return false; -#endif - - boost::archive::binary_oarchive a(data_file); - a << obj; - if (data_file.fail()) - return false; - - data_file.flush(); -#ifdef _WIN32 - // To make sure the file is fully stored on disk - ::FlushFileBuffers(data_file_handle); - fclose(data_file_file); -#endif - - return true; - } catch (std::exception&) { +template +bool serialize_obj_to_file(t_object& obj, const std::string& file_path) { + try { + std::ofstream file(file_path); + boost::archive::binary_oarchive a(file); + a << obj; + if (file.fail()) { return false; } - } - template - bool unserialize_obj_from_file(t_object& obj, const std::string& file_path) - { - try { - std::ifstream data_file; - data_file.open( file_path, std::ios_base::binary | std::ios_base::in); - if(data_file.fail()) - return false; - boost::archive::binary_iarchive a(data_file); - - a >> obj; - return !data_file.fail(); - } catch (std::exception&) { - return false; - } + file.flush(); + return true; + } catch (std::exception&) { + return false; } } + +template +bool unserialize_obj_from_file(t_object& obj, const std::string& file_path) { + try { + std::ifstream dataFile; + dataFile.open(file_path, std::ios_base::binary | std::ios_base::in); + if (dataFile.fail()) { + return false; + } + + boost::archive::binary_iarchive a(dataFile); + a >> obj; + return !dataFile.fail(); + } catch (std::exception&) { + return false; + } +} + +} diff --git a/tests/CoreTests/ChaingenMain.cpp b/tests/CoreTests/ChaingenMain.cpp index 93c4690b..b81eb3d2 100644 --- a/tests/CoreTests/ChaingenMain.cpp +++ b/tests/CoreTests/ChaingenMain.cpp @@ -150,6 +150,8 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(gen_tx_txout_to_key_has_invalid_key); GENERATE_AND_PLAY(gen_tx_output_with_zero_amount); GENERATE_AND_PLAY(gen_tx_signatures_are_invalid); + GENERATE_AND_PLAY_EX(GenerateTransactionWithZeroFee(false)); + GENERATE_AND_PLAY_EX(GenerateTransactionWithZeroFee(true)); // multisignature output GENERATE_AND_PLAY_EX(MultiSigTx_OutputSignatures(1, 1, true)); @@ -187,7 +189,7 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY_EX(MultiSigTx_DoubleSpendInTx(false)); GENERATE_AND_PLAY_EX(MultiSigTx_DoubleSpendInTx(true)); GENERATE_AND_PLAY_EX(MultiSigTx_DoubleSpendSameBlock(false)); - GENERATE_AND_PLAY_EX(MultiSigTx_DoubleSpendSameBlock(true)); + GENERATE_AND_PLAY_EX(MultiSigTx_DoubleSpendSameBlock(true)); GENERATE_AND_PLAY_EX(MultiSigTx_DoubleSpendDifferentBlocks(false)); GENERATE_AND_PLAY_EX(MultiSigTx_DoubleSpendDifferentBlocks(true)); GENERATE_AND_PLAY_EX(MultiSigTx_DoubleSpendAltChainSameBlock(false)); diff --git a/tests/CoreTests/TransactionValidation.cpp b/tests/CoreTests/TransactionValidation.cpp index ad027477..7b4d2890 100644 --- a/tests/CoreTests/TransactionValidation.cpp +++ b/tests/CoreTests/TransactionValidation.cpp @@ -682,6 +682,34 @@ bool gen_tx_signatures_are_invalid::generate(std::vector& even return true; } +GenerateTransactionWithZeroFee::GenerateTransactionWithZeroFee(bool keptByBlock) : m_keptByBlock(keptByBlock) { +} + +bool GenerateTransactionWithZeroFee::generate(std::vector& events) const { + uint64_t ts_start = 1338224400; + + GENERATE_ACCOUNT(alice_account); + GENERATE_ACCOUNT(bob_account); + MAKE_GENESIS_BLOCK(events, blk_0, alice_account, ts_start); + REWIND_BLOCKS(events, blk_0r, blk_0, alice_account); + + CryptoNote::Transaction tx; + construct_tx_to_key(m_logger, events, tx, blk_0, alice_account, bob_account, MK_COINS(1), 0, 0); + + if (!m_keptByBlock) { + DO_CALLBACK(events, "mark_invalid_tx"); + } else { + event_visitor_settings settings; + settings.txs_keeped_by_block = true; + settings.valid_mask = 1; + events.push_back(settings); + } + + events.push_back(tx); + + return true; +} + MultiSigTx_OutputSignatures::MultiSigTx_OutputSignatures(size_t givenKeys, uint32_t requiredSignatures, bool shouldSucceed) : m_givenKeys(givenKeys), m_requiredSignatures(requiredSignatures), m_shouldSucceed(shouldSucceed) { diff --git a/tests/CoreTests/TransactionValidation.h b/tests/CoreTests/TransactionValidation.h index 7da9ece5..66be839e 100755 --- a/tests/CoreTests/TransactionValidation.h +++ b/tests/CoreTests/TransactionValidation.h @@ -141,6 +141,14 @@ struct gen_tx_signatures_are_invalid : public get_tx_validation_base bool generate(std::vector& events) const; }; +struct GenerateTransactionWithZeroFee : public get_tx_validation_base +{ + explicit GenerateTransactionWithZeroFee(bool keptByBlock); + bool generate(std::vector& events) const; + + bool m_keptByBlock; +}; + // MultiSignature class TestGenerator; diff --git a/tests/System/ErrorMessageTests.cpp b/tests/System/ErrorMessageTests.cpp new file mode 100644 index 00000000..00d1944d --- /dev/null +++ b/tests/System/ErrorMessageTests.cpp @@ -0,0 +1,26 @@ +// Copyright (c) 2012-2015, The CryptoNote developers, The Bytecoin developers +// +// This file is part of Bytecoin. +// +// Bytecoin is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Bytecoin is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Bytecoin. If not, see . + +#include +#include + +using namespace System; + +TEST(ErrorMessageTests, testErrorMessage) { + auto msg = errorMessage(100); + ASSERT_EQ(msg.substr(0, 12), "result=100, "); +} diff --git a/tests/UnitTests/INodeStubs.cpp b/tests/UnitTests/INodeStubs.cpp index 901b0f4b..be0da74a 100644 --- a/tests/UnitTests/INodeStubs.cpp +++ b/tests/UnitTests/INodeStubs.cpp @@ -291,6 +291,10 @@ void INodeTrivialRefreshStub::setNextTransactionToPool() { m_nextTxToPool = true; } +void INodeTrivialRefreshStub::cleanTransactionPool() { + m_blockchainGenerator.clearTxPool(); +} + void INodeTrivialRefreshStub::getPoolSymmetricDifference(std::vector&& known_pool_tx_ids, Crypto::Hash known_block_id, bool& is_bc_actual, std::vector>& new_txs, std::vector& deleted_tx_ids, const Callback& callback) { diff --git a/tests/UnitTests/INodeStubs.h b/tests/UnitTests/INodeStubs.h index ba9f892f..33aef2af 100644 --- a/tests/UnitTests/INodeStubs.h +++ b/tests/UnitTests/INodeStubs.h @@ -104,6 +104,7 @@ public: virtual void startAlternativeChain(uint32_t height); void setNextTransactionError(); void setNextTransactionToPool(); + void cleanTransactionPool(); void setMaxMixinCount(uint64_t maxMixin); void includeTransactionsFromPoolToBlock(); diff --git a/tests/UnitTests/TestWalletLegacy.cpp b/tests/UnitTests/TestWalletLegacy.cpp index 4973a66e..5e8943a0 100644 --- a/tests/UnitTests/TestWalletLegacy.cpp +++ b/tests/UnitTests/TestWalletLegacy.cpp @@ -61,8 +61,8 @@ public: } virtual void synchronizationCompleted(std::error_code result) override { - synced.notify(); - } + synced.notify(); + } virtual void sendTransactionCompleted(CryptoNote::TransactionId transactionId, std::error_code result) override { sendResult = result; @@ -166,6 +166,9 @@ protected: void prepareCarolWallet(); void GetOneBlockReward(CryptoNote::WalletLegacy& wallet); + void GetOneBlockReward(CryptoNote::WalletLegacy& wallet, const CryptoNote::Currency& currency, TestBlockchainGenerator& blockchainGenerator); + void GetOneBlockRewardAndUnlock(CryptoNote::WalletLegacy& wallet, TrivialWalletObserver& observer, INodeTrivialRefreshStub& node, + const CryptoNote::Currency& currency, TestBlockchainGenerator& blockchainGenerator); void TestSendMoney(int64_t transferAmount, uint64_t fee, uint64_t mixIn = 0, const std::string& extra = ""); void performTransferWithErrorTx(const std::array& amounts, uint64_t fee); @@ -221,9 +224,21 @@ void WalletLegacyApi::prepareCarolWallet() { } void WalletLegacyApi::GetOneBlockReward(CryptoNote::WalletLegacy& wallet) { + GetOneBlockReward(wallet, m_currency, generator); +} + +void WalletLegacyApi::GetOneBlockReward(CryptoNote::WalletLegacy& wallet, const CryptoNote::Currency& currency, TestBlockchainGenerator& blockchainGenerator) { CryptoNote::AccountPublicAddress address; - ASSERT_TRUE(m_currency.parseAccountAddressString(wallet.getAddress(), address)); - generator.getBlockRewardForAddress(address); + ASSERT_TRUE(currency.parseAccountAddressString(wallet.getAddress(), address)); + blockchainGenerator.getBlockRewardForAddress(address); +} + +void WalletLegacyApi::GetOneBlockRewardAndUnlock(CryptoNote::WalletLegacy& wallet, TrivialWalletObserver& observer, INodeTrivialRefreshStub& node, + const CryptoNote::Currency& currency, TestBlockchainGenerator& blockchainGenerator) { + GetOneBlockReward(wallet, currency, blockchainGenerator); + blockchainGenerator.generateEmptyBlocks(10); + node.updateObservers(); + WaitWalletSync(&observer); } void WalletLegacyApi::performTransferWithErrorTx(const std::array& amounts, uint64_t fee) { @@ -1720,3 +1735,86 @@ TEST_F(WalletLegacyApi, resetAndSyncDoNotRestoreTransfers) { alice->shutdown(); } + +void generateWallet(CryptoNote::IWalletLegacy& wallet, TrivialWalletObserver& observer, const std::string& pass) { + wallet.initAndGenerate(pass); + WaitWalletSync(&observer); +} + +TEST_F(WalletLegacyApi, outdatedUnconfirmedTransactionDeletedOnNewBlock) { + const uint64_t TRANSACTION_MEMPOOL_TIME = 1; + CryptoNote::Currency currency(CryptoNote::CurrencyBuilder(m_logger).mempoolTxLiveTime(TRANSACTION_MEMPOOL_TIME).currency()); + TestBlockchainGenerator blockchainGenerator(currency); + INodeTrivialRefreshStub node(blockchainGenerator); + CryptoNote::WalletLegacy wallet(currency, node); + TrivialWalletObserver walletObserver; + wallet.addObserver(&walletObserver); + + wallet.initAndGenerate("pass"); + WaitWalletSync(&walletObserver); + + GetOneBlockRewardAndUnlock(wallet, walletObserver, node, currency, blockchainGenerator); + + const std::string ADDRESS = "2634US2FAz86jZT73YmM8u5GPCknT2Wxj8bUCKivYKpThFhF2xsjygMGxbxZzM42zXhKUhym6Yy6qHHgkuWtruqiGkDpX6m"; + node.setNextTransactionToPool(); + auto id = wallet.sendTransaction({ADDRESS, static_cast(TEST_BLOCK_REWARD - m_currency.minimumFee())}, m_currency.minimumFee()); + WaitWalletSend(&walletObserver); + + node.cleanTransactionPool(); + std::this_thread::sleep_for(std::chrono::seconds(TRANSACTION_MEMPOOL_TIME)); + + blockchainGenerator.generateEmptyBlocks(1); + node.updateObservers(); + WaitWalletSync(&walletObserver); + + ASSERT_EQ(TEST_BLOCK_REWARD, wallet.actualBalance()); + + CryptoNote::WalletLegacyTransaction transaction; + ASSERT_TRUE(wallet.getTransaction(id, transaction)); + EXPECT_EQ(CryptoNote::WalletLegacyTransactionState::Deleted, transaction.state); + + wallet.removeObserver(&walletObserver); + wallet.shutdown(); +} + +TEST_F(WalletLegacyApi, outdatedUnconfirmedTransactionDeletedOnLoad) { + const uint64_t TRANSACTION_MEMPOOL_TIME = 1; + CryptoNote::Currency currency(CryptoNote::CurrencyBuilder(m_logger).mempoolTxLiveTime(TRANSACTION_MEMPOOL_TIME).currency()); + TestBlockchainGenerator blockchainGenerator(currency); + INodeTrivialRefreshStub node(blockchainGenerator); + CryptoNote::WalletLegacy wallet(currency, node); + TrivialWalletObserver walletObserver; + wallet.addObserver(&walletObserver); + + wallet.initAndGenerate("pass"); + WaitWalletSync(&walletObserver); + + GetOneBlockRewardAndUnlock(wallet, walletObserver, node, currency, blockchainGenerator); + + const std::string ADDRESS = "2634US2FAz86jZT73YmM8u5GPCknT2Wxj8bUCKivYKpThFhF2xsjygMGxbxZzM42zXhKUhym6Yy6qHHgkuWtruqiGkDpX6m"; + node.setNextTransactionToPool(); + auto id = wallet.sendTransaction({ADDRESS, static_cast(TEST_BLOCK_REWARD - m_currency.minimumFee())}, m_currency.minimumFee()); + WaitWalletSend(&walletObserver); + + node.cleanTransactionPool(); + + std::stringstream data; + wallet.save(data); + WaitWalletSave(&walletObserver); + + wallet.shutdown(); + + std::this_thread::sleep_for(std::chrono::seconds(TRANSACTION_MEMPOOL_TIME)); + + wallet.initAndLoad(data, "pass"); + WaitWalletSync(&walletObserver); + + ASSERT_EQ(TEST_BLOCK_REWARD, wallet.actualBalance()); + + CryptoNote::WalletLegacyTransaction transaction; + ASSERT_TRUE(wallet.getTransaction(id, transaction)); + EXPECT_EQ(CryptoNote::WalletLegacyTransactionState::Deleted, transaction.state); + + wallet.removeObserver(&walletObserver); + wallet.shutdown(); +}