diff options
77 files changed, 1726 insertions, 595 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 842eea734..1f74f59e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -234,6 +234,7 @@ if(STATIC) else() set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) endif() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DZMQ_STATIC") endif() # Set default blockchain storage location: @@ -319,6 +320,12 @@ else() message(STATUS "Stack trace on exception disabled") endif() +if (UNIX AND NOT APPLE) + # Note that at the time of this writing the -Wstrict-prototypes flag added below will make this fail + set(THREADS_PREFER_PTHREAD_FLAG ON) + find_package(Threads) +endif() + # Handle OpenSSL, used for sha256sum on binary updates if (APPLE AND NOT IOS) if (NOT OpenSSL_DIR) @@ -332,16 +339,10 @@ endif() find_package(OpenSSL REQUIRED) if(STATIC AND NOT IOS) if(UNIX) - set(OPENSSL_LIBRARIES "${OPENSSL_LIBRARIES};${CMAKE_DL_LIBS}") + set(OPENSSL_LIBRARIES "${OPENSSL_LIBRARIES};${CMAKE_DL_LIBS};${CMAKE_THREAD_LIBS_INIT}") endif() endif() -if (UNIX AND NOT APPLE) - # Note that at the time of this writing the -Wstrict-prototypes flag added below will make this fail - set(THREADS_PREFER_PTHREAD_FLAG ON) - find_package(Threads) -endif() - add_definitions(-DAUTO_INITIALIZE_EASYLOGGINGPP) add_subdirectory(external) @@ -691,12 +692,16 @@ include(version.cmake) find_path(ZMQ_INCLUDE_PATH zmq.hpp) find_library(ZMQ_LIB zmq) +find_library(SODIUM_LIBRARY sodium) if(NOT ZMQ_INCLUDE_PATH) message(FATAL_ERROR "Could not find required header zmq.hpp") endif() if(NOT ZMQ_LIB) - message(FATAL_ERROR "Could not find require libzmq") + message(FATAL_ERROR "Could not find required libzmq") +endif() +if(SODIUM_LIBRARY) + set(ZMQ_LIB "${ZMQ_LIB};${SODIUM_LIBRARY}") endif() option(BUILD_TESTS "Build tests." OFF) @@ -222,13 +222,13 @@ invokes cmake commands as needed. HAVE_DOT=YES doxygen Doxyfile -#### On the Raspberry Pi 2 +#### On the Raspberry Pi -Tested on a Raspberry Pi 2 with a clean install of minimal Debian Jessie from https://www.raspberrypi.org/downloads/raspbian/ +Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (2017-09-07 or later) from https://www.raspberrypi.org/downloads/raspbian/. If you are using Raspian Jessie, [please see note in the following section](#note-for-raspbian-jessie-users). * `apt-get update && apt-get upgrade` to install all of the latest software -* Install the dependencies for Monero except libunwind and libboost-all-dev +* Install the dependencies for Monero from the 'Debian' column in the table above. * Increase the system swap size: ``` @@ -237,6 +237,41 @@ Tested on a Raspberry Pi 2 with a clean install of minimal Debian Jessie from ht CONF_SWAPSIZE=1024 sudo /etc/init.d/dphys-swapfile start ``` +* Clone monero and checkout most recent release version: +``` + git clone https://github.com/monero-project/monero.git + cd monero + git checkout tags/v0.11.0.0 +``` +* Build: +``` + make release +``` +* Wait 4-6 hours + +* The resulting executables can be found in `build/release/bin` + +* Add `PATH="$PATH:$HOME/monero/build/release/bin"` to `.profile` + +* Run Monero with `monerod --detach` + +* You may wish to reduce the size of the swap file after the build has finished, and delete the boost directory from your home directory + +#### *Note for Raspbian Jessie Users:* + +If you are using the older Raspbian Jessie image, compiling Monero is a bit more complicated. The version of Boost available in the Debian Jessie repositories is too old to use with Monero, and thus you must compile a newer version yourself. The following explains the extra steps, and has been tested on a Raspberry Pi 2 with a clean install of minimal Raspbian Jessie. + +* As before, `apt-get update && apt-get upgrade` to install all of the latest software, and increase the system swap size + +``` + sudo /etc/init.d/dphys-swapfile stop + sudo nano /etc/dphys-swapfile + CONF_SWAPSIZE=1024 + sudo /etc/init.d/dphys-swapfile start +``` + +* Then, install the dependencies for Monero except `libunwind` and `libboost-all-dev` + * Install the latest version of boost (this may first require invoking `apt-get remove --purge libboost*` to remove a previous version if you're not using a clean install): ``` cd @@ -252,20 +287,7 @@ Tested on a Raspberry Pi 2 with a clean install of minimal Debian Jessie from ht ``` * Wait ~4 hours -* Change to the root of the source code directory and build: -``` - cd monero - make release -``` -* Wait ~4 hours - -* The resulting executables can be found in `build/release/bin` - -* Add `PATH="$PATH:$HOME/monero/build/release/bin"` to `.profile` - -* Run Monero with `monerod --detach` - -* You may wish to reduce the size of the swap file after the build has finished, and delete the boost directory from your home directory +* From here, follow the [general Raspberry Pi instructions](#on-the-raspberry-pi) from the "Clone monero and checkout most recent release version" step. #### On Windows: diff --git a/contrib/epee/include/misc_log_ex.h b/contrib/epee/include/misc_log_ex.h index d351b024d..982aaea06 100644 --- a/contrib/epee/include/misc_log_ex.h +++ b/contrib/epee/include/misc_log_ex.h @@ -126,6 +126,7 @@ std::string mlog_get_default_log_path(const char *default_filename); void mlog_configure(const std::string &filename_base, bool console, const std::size_t max_log_file_size = MAX_LOG_FILE_SIZE); void mlog_set_categories(const char *categories); +std::string mlog_get_categories(); void mlog_set_log_level(int level); void mlog_set_log(const char *log); diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl index 76988a26e..94ef7c3b3 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -137,14 +137,14 @@ PRAGMA_WARNING_DISABLE_VS(4355) CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to get local endpoint: " << ec.message() << ':' << ec.value()); context = boost::value_initialized<t_connection_context>(); - long ip_ = boost::asio::detail::socket_ops::host_to_network_long(remote_ep.address().to_v4().to_ulong()); + const unsigned long ip_{boost::asio::detail::socket_ops::host_to_network_long(remote_ep.address().to_v4().to_ulong())}; // create a random uuid boost::uuids::uuid random_uuid; // that stuff turns out to be included, even though it's from src... Taking advantage random_uuid = crypto::rand<boost::uuids::uuid>(); - context.set_details(random_uuid, new epee::net_utils::ipv4_network_address(ip_, remote_ep.port()), is_income); + context.set_details(random_uuid, epee::net_utils::ipv4_network_address(ip_, remote_ep.port()), is_income); _dbg3("[sock " << socket_.native_handle() << "] new connection from " << print_connection_context_short(context) << " to " << local_ep.address().to_string() << ':' << local_ep.port() << ", total sockets objects " << m_ref_sock_count); diff --git a/contrib/epee/include/net/levin_protocol_handler_async.h b/contrib/epee/include/net/levin_protocol_handler_async.h index 60a667690..779f4e78f 100644 --- a/contrib/epee/include/net/levin_protocol_handler_async.h +++ b/contrib/epee/include/net/levin_protocol_handler_async.h @@ -740,9 +740,15 @@ void async_protocol_handler_config<t_connection_context>::del_out_connections(si shuffle(out_connections.begin(), out_connections.end(), std::default_random_engine(seed)); while (count > 0 && out_connections.size() > 0) { - close(*out_connections.begin()); - del_connection(m_connects.at(*out_connections.begin())); + boost::uuids::uuid connection_id = *out_connections.begin(); + async_protocol_handler<t_connection_context> *connection = find_connection(connection_id); + // we temporarily ref the connection so it doesn't drop from the m_connects table + // when we close it + connection->start_outer_call(); + close(connection_id); + del_connection(m_connects.at(connection_id)); out_connections.erase(out_connections.begin()); + connection->finish_outer_call(); --count; } diff --git a/contrib/epee/include/net/net_utils_base.h b/contrib/epee/include/net/net_utils_base.h index ef3a1d146..0e31ee86f 100644 --- a/contrib/epee/include/net/net_utils_base.h +++ b/contrib/epee/include/net/net_utils_base.h @@ -29,11 +29,12 @@ #ifndef _NET_UTILS_BASE_H_ #define _NET_UTILS_BASE_H_ -#include <typeinfo> #include <boost/asio/io_service.hpp> #include <boost/uuid/uuid.hpp> +#include <memory> +#include <typeinfo> +#include <type_traits> #include "serialization/keyvalue_serialization.h" -#include "net/local_ip.h" #include "string_tools.h" #include "misc_log_ex.h" @@ -49,75 +50,119 @@ namespace epee { namespace net_utils { - struct network_address_base + class ipv4_network_address { - public: - bool operator==(const network_address_base &other) const { return m_full_id == other.m_full_id; } - bool operator!=(const network_address_base &other) const { return !operator==(other); } - bool operator<(const network_address_base &other) const { return m_full_id < other.m_full_id; } - bool is_same_host(const network_address_base &other) const { return m_host_id == other.m_host_id; } - virtual std::string str() const = 0; - virtual std::string host_str() const = 0; - virtual bool is_loopback() const = 0; - virtual bool is_local() const = 0; - virtual uint8_t get_type_id() const = 0; - protected: - // A very simple non cryptographic hash function by Fowler, Noll, Vo - uint64_t fnv1a(const uint8_t *data, size_t len) const { - uint64_t h = 0xcbf29ce484222325; - while (len--) - h = (h ^ *data++) * 0x100000001b3; - return h; - } - uint64_t m_host_id; - uint64_t m_full_id; - }; - struct ipv4_network_address: public network_address_base - { - void init_ids() - { - m_host_id = fnv1a((const uint8_t*)&m_ip, sizeof(m_ip)); - m_full_id = fnv1a((const uint8_t*)&m_ip, sizeof(m_ip) + sizeof(m_port)); - } - public: - ipv4_network_address(uint32_t ip, uint16_t port): network_address_base(), m_ip(ip), m_port(port) { init_ids(); } - uint32_t ip() const { return m_ip; } - uint16_t port() const { return m_port; } - virtual std::string str() const { return epee::string_tools::get_ip_string_from_int32(m_ip) + ":" + std::to_string(m_port); } - virtual std::string host_str() const { return epee::string_tools::get_ip_string_from_int32(m_ip); } - virtual bool is_loopback() const { return epee::net_utils::is_ip_loopback(m_ip); } - virtual bool is_local() const { return epee::net_utils::is_ip_local(m_ip); } - virtual uint8_t get_type_id() const { return ID; } - public: // serialization - static const uint8_t ID = 1; -#pragma pack(push) -#pragma pack(1) uint32_t m_ip; uint16_t m_port; -#pragma pack(pop) + + public: + constexpr ipv4_network_address(uint32_t ip, uint16_t port) noexcept + : m_ip(ip), m_port(port) {} + + bool equal(const ipv4_network_address& other) const noexcept; + bool less(const ipv4_network_address& other) const noexcept; + constexpr bool is_same_host(const ipv4_network_address& other) const noexcept + { return ip() == other.ip(); } + + constexpr uint32_t ip() const noexcept { return m_ip; } + constexpr uint16_t port() const noexcept { return m_port; } + std::string str() const; + std::string host_str() const; + bool is_loopback() const; + bool is_local() const; + static constexpr uint8_t get_type_id() noexcept { return ID; } + + static const uint8_t ID = 1; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(m_ip) KV_SERIALIZE(m_port) - if (!is_store) - const_cast<ipv4_network_address&>(this_ref).init_ids(); END_KV_SERIALIZE_MAP() }; - class network_address: public boost::shared_ptr<network_address_base> + + inline bool operator==(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept + { return lhs.equal(rhs); } + inline bool operator!=(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept + { return !lhs.equal(rhs); } + inline bool operator<(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept + { return lhs.less(rhs); } + inline bool operator<=(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept + { return !rhs.less(lhs); } + inline bool operator>(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept + { return rhs.less(lhs); } + inline bool operator>=(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept + { return !lhs.less(rhs); } + + class network_address { + struct interface + { + virtual ~interface() {}; + + virtual bool equal(const interface&) const = 0; + virtual bool less(const interface&) const = 0; + virtual bool is_same_host(const interface&) const = 0; + + virtual std::string str() const = 0; + virtual std::string host_str() const = 0; + virtual bool is_loopback() const = 0; + virtual bool is_local() const = 0; + virtual uint8_t get_type_id() const = 0; + }; + + template<typename T> + struct implementation final : interface + { + T value; + + implementation(const T& src) : value(src) {} + ~implementation() = default; + + // Type-checks for cast are done in cpp + static const T& cast(const interface& src) noexcept + { return static_cast<const implementation<T>&>(src).value; } + + virtual bool equal(const interface& other) const override + { return value.equal(cast(other)); } + + virtual bool less(const interface& other) const override + { return value.less(cast(other)); } + + virtual bool is_same_host(const interface& other) const override + { return value.is_same_host(cast(other)); } + + virtual std::string str() const override { return value.str(); } + virtual std::string host_str() const override { return value.host_str(); } + virtual bool is_loopback() const override { return value.is_loopback(); } + virtual bool is_local() const override { return value.is_local(); } + virtual uint8_t get_type_id() const override { return value.get_type_id(); } + }; + + std::shared_ptr<interface> self; + + template<typename Type> + Type& as_mutable() const + { + // types `implmentation<Type>` and `implementation<const Type>` are unique + using Type_ = typename std::remove_const<Type>::type; + network_address::interface* const self_ = self.get(); // avoid clang warning in typeid + if (!self_ || typeid(implementation<Type_>) != typeid(*self_)) + throw std::bad_cast{}; + return static_cast<implementation<Type_>*>(self_)->value; + } public: - network_address() {} - network_address(ipv4_network_address *address): boost::shared_ptr<network_address_base>(address) {} - bool operator==(const network_address &other) const { return (*this)->operator==(*other); } - bool operator!=(const network_address &other) const { return (*this)->operator!=(*other); } - bool operator<(const network_address &other) const { return (*this)->operator<(*other); } - bool is_same_host(const network_address &other) const { return (*this)->is_same_host(*other); } - std::string str() const { return (*this) ? (*this)->str() : "<none>"; } - std::string host_str() const { return (*this) ? (*this)->host_str() : "<none>"; } - bool is_loopback() const { return (*this)->is_loopback(); } - bool is_local() const { return (*this)->is_local(); } - uint8_t get_type_id() const { return (*this)->get_type_id(); } - template<typename Type> Type &as() { if (get_type_id() != Type::ID) throw std::runtime_error("Bad type"); return *(Type*)get(); } - template<typename Type> const Type &as() const { if (get_type_id() != Type::ID) throw std::runtime_error("Bad type"); return *(const Type*)get(); } + network_address() : self(nullptr) {} + template<typename T> + network_address(const T& src) + : self(std::make_shared<implementation<T>>(src)) {} + bool equal(const network_address &other) const; + bool less(const network_address &other) const; + bool is_same_host(const network_address &other) const; + std::string str() const { return self ? self->str() : "<none>"; } + std::string host_str() const { return self ? self->host_str() : "<none>"; } + bool is_loopback() const { return self ? self->is_loopback() : false; } + bool is_local() const { return self ? self->is_local() : false; } + uint8_t get_type_id() const { return self ? self->get_type_id() : 0; } + template<typename Type> const Type &as() const { return as_mutable<const Type>(); } BEGIN_KV_SERIALIZE_MAP() uint8_t type = is_store ? this_ref.get_type_id() : 0; @@ -126,13 +171,27 @@ namespace net_utils { case ipv4_network_address::ID: if (!is_store) - const_cast<network_address&>(this_ref).reset(new ipv4_network_address(0, 0)); - KV_SERIALIZE(template as<ipv4_network_address>()); + const_cast<network_address&>(this_ref) = ipv4_network_address{0, 0}; + KV_SERIALIZE(template as_mutable<ipv4_network_address>()); break; default: MERROR("Unsupported network address type: " << type); return false; } END_KV_SERIALIZE_MAP() }; + + inline bool operator==(const network_address& lhs, const network_address& rhs) + { return lhs.equal(rhs); } + inline bool operator!=(const network_address& lhs, const network_address& rhs) + { return !lhs.equal(rhs); } + inline bool operator<(const network_address& lhs, const network_address& rhs) + { return lhs.less(rhs); } + inline bool operator<=(const network_address& lhs, const network_address& rhs) + { return !rhs.less(lhs); } + inline bool operator>(const network_address& lhs, const network_address& rhs) + { return rhs.less(lhs); } + inline bool operator>=(const network_address& lhs, const network_address& rhs) + { return !lhs.less(rhs); } + inline bool create_network_address(network_address &address, const std::string &string, uint16_t default_port = 0) { uint32_t ip; @@ -141,7 +200,7 @@ namespace net_utils { if (default_port && !port) port = default_port; - address.reset(new ipv4_network_address(ip, port)); + address = ipv4_network_address{ip, port}; return true; } return false; @@ -179,7 +238,7 @@ namespace net_utils {} connection_context_base(): m_connection_id(), - m_remote_address(new ipv4_network_address(0,0)), + m_remote_address(ipv4_network_address{0,0}), m_is_income(false), m_started(time(NULL)), m_last_recv(0), @@ -232,7 +291,7 @@ namespace net_utils std::string print_connection_context(const connection_context_base& ctx) { std::stringstream ss; - ss << ctx.m_remote_address->str() << " " << epee::string_tools::get_str_from_guid_a(ctx.m_connection_id) << (ctx.m_is_income ? " INC":" OUT"); + ss << ctx.m_remote_address.str() << " " << epee::string_tools::get_str_from_guid_a(ctx.m_connection_id) << (ctx.m_is_income ? " INC":" OUT"); return ss.str(); } @@ -240,7 +299,7 @@ namespace net_utils std::string print_connection_context_short(const connection_context_base& ctx) { std::stringstream ss; - ss << ctx.m_remote_address->str() << (ctx.m_is_income ? " INC":" OUT"); + ss << ctx.m_remote_address.str() << (ctx.m_is_income ? " INC":" OUT"); return ss.str(); } diff --git a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h index 1a58cab99..4423f2608 100644 --- a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h +++ b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h @@ -227,6 +227,18 @@ namespace epee } //------------------------------------------------------------------------------------------------------------------- template<class t_type, class t_storage> + static bool kv_serialize(const std::deque<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return serialize_stl_container_t_val(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template<class t_type, class t_storage> + static bool kv_unserialize(std::deque<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return unserialize_stl_container_t_val(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template<class t_type, class t_storage> static bool kv_serialize(const std::list<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) { return serialize_stl_container_t_val(d, stg, hparent_section, pname); @@ -268,6 +280,18 @@ namespace epee } //------------------------------------------------------------------------------------------------------------------- template<class t_type, class t_storage> + static bool kv_serialize(const std::deque<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return serialize_stl_container_t_obj(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template<class t_type, class t_storage> + static bool kv_unserialize(std::deque<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return unserialize_stl_container_t_obj(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template<class t_type, class t_storage> static bool kv_serialize(const std::list<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) { return serialize_stl_container_t_obj(d, stg, hparent_section, pname); @@ -353,6 +377,18 @@ namespace epee } //------------------------------------------------------------------------------------------------------------------- template<class t_type, class t_storage> + bool kv_serialize(const std::deque<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types<t_storage>, typename std::remove_const<t_type>::type>::value>::kv_serialize(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template<class t_type, class t_storage> + bool kv_unserialize(std::deque<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types<t_storage>, typename std::remove_const<t_type>::type>::value>::kv_unserialize(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template<class t_type, class t_storage> bool kv_serialize(const std::list<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) { return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types<t_storage>, typename std::remove_const<t_type>::type>::value>::kv_serialize(d, stg, hparent_section, pname); diff --git a/contrib/epee/src/CMakeLists.txt b/contrib/epee/src/CMakeLists.txt index c61a6e684..294515f83 100644 --- a/contrib/epee/src/CMakeLists.txt +++ b/contrib/epee/src/CMakeLists.txt @@ -27,9 +27,9 @@ # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. if (USE_READLINE AND GNU_READLINE_FOUND) - add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp string_tools.cpp readline_buffer.cpp) + add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp net_utils_base.cpp string_tools.cpp readline_buffer.cpp) else() - add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp string_tools.cpp) + add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp net_utils_base.cpp string_tools.cpp) endif() # Build and install libepee if we're building for GUI diff --git a/contrib/epee/src/mlog.cpp b/contrib/epee/src/mlog.cpp index 964ba41df..cfb2b7b15 100644 --- a/contrib/epee/src/mlog.cpp +++ b/contrib/epee/src/mlog.cpp @@ -144,16 +144,52 @@ void mlog_configure(const std::string &filename_base, bool console, const std::s void mlog_set_categories(const char *categories) { - el::Loggers::setCategories(categories); - MLOG_LOG("New log categories: " << categories); + std::string new_categories; + if (*categories) + { + if (*categories == '+') + { + ++categories; + new_categories = mlog_get_categories(); + if (*categories) + { + if (!new_categories.empty()) + new_categories += ","; + new_categories += categories; + } + } + else if (*categories == '-') + { + ++categories; + new_categories = mlog_get_categories(); + std::vector<std::string> single_categories; + boost::split(single_categories, categories, boost::is_any_of(","), boost::token_compress_on); + for (const std::string &s: single_categories) + { + size_t pos = new_categories.find(s); + if (pos != std::string::npos) + new_categories = new_categories.erase(pos, s.size()); + } + } + else + { + new_categories = categories; + } + } + el::Loggers::setCategories(new_categories.c_str(), true); + MLOG_LOG("New log categories: " << el::Loggers::getCategories()); +} + +std::string mlog_get_categories() +{ + return el::Loggers::getCategories(); } // maps epee style log level to new logging system void mlog_set_log_level(int level) { const char *categories = get_default_categories(level); - el::Loggers::setCategories(categories); - MLOG_LOG("New log categories: " << categories); + mlog_set_categories(categories); } void mlog_set_log(const char *log) diff --git a/contrib/epee/src/net_utils_base.cpp b/contrib/epee/src/net_utils_base.cpp new file mode 100644 index 000000000..22afcf819 --- /dev/null +++ b/contrib/epee/src/net_utils_base.cpp @@ -0,0 +1,60 @@ + +#include "net/net_utils_base.h" + +#include <cstring> +#include <typeindex> +#include "net/local_ip.h" + +namespace epee { namespace net_utils +{ + const uint8_t ipv4_network_address::ID; + + bool ipv4_network_address::equal(const ipv4_network_address& other) const noexcept + { return is_same_host(other) && port() == other.port(); } + + bool ipv4_network_address::less(const ipv4_network_address& other) const noexcept + { return is_same_host(other) ? port() < other.port() : ip() < other.ip(); } + + std::string ipv4_network_address::str() const + { return string_tools::get_ip_string_from_int32(ip()) + ":" + std::to_string(port()); } + + std::string ipv4_network_address::host_str() const { return string_tools::get_ip_string_from_int32(ip()); } + bool ipv4_network_address::is_loopback() const { return net_utils::is_ip_loopback(ip()); } + bool ipv4_network_address::is_local() const { return net_utils::is_ip_local(ip()); } + + + bool network_address::equal(const network_address& other) const + { + // clang typeid workaround + network_address::interface const* const self_ = self.get(); + network_address::interface const* const other_self = other.self.get(); + if (self_ == other_self) return true; + if (!self_ || !other_self) return false; + if (typeid(*self_) != typeid(*other_self)) return false; + return self_->equal(*other_self); + } + + bool network_address::less(const network_address& other) const + { + // clang typeid workaround + network_address::interface const* const self_ = self.get(); + network_address::interface const* const other_self = other.self.get(); + if (self_ == other_self) return false; + if (!self_ || !other_self) return self == nullptr; + if (typeid(*self_) != typeid(*other_self)) + return self_->get_type_id() < other_self->get_type_id(); + return self_->less(*other_self); + } + + bool network_address::is_same_host(const network_address& other) const + { + // clang typeid workaround + network_address::interface const* const self_ = self.get(); + network_address::interface const* const other_self = other.self.get(); + if (self_ == other_self) return true; + if (!self_ || !other_self) return false; + if (typeid(*self_) != typeid(*other_self)) return false; + return self_->is_same_host(*other_self); + } +}} + diff --git a/external/db_drivers/liblmdb/mdb_load.1 b/external/db_drivers/liblmdb/mdb_load.1 index 712ed0540..ede3702d9 100644 --- a/external/db_drivers/liblmdb/mdb_load.1 +++ b/external/db_drivers/liblmdb/mdb_load.1 @@ -37,6 +37,13 @@ option below. .BR \-V Write the library version number to the standard output, and exit. .TP +.BR \-a +Append all records in the order they appear in the input. The input is assumed to already be +in correctly sorted order and no sorting or checking for redundant values will be performed. +This option must be used to reload data that was produced by running +.B mdb_dump +on a database that uses custom compare functions. +.TP .BR \-f \ file Read from the specified file instead of from the standard input. .TP diff --git a/external/db_drivers/liblmdb/mdb_load.c b/external/db_drivers/liblmdb/mdb_load.c index d1fda4bf5..797c2f979 100644 --- a/external/db_drivers/liblmdb/mdb_load.c +++ b/external/db_drivers/liblmdb/mdb_load.c @@ -37,6 +37,7 @@ static int Eof; static MDB_envinfo info; static MDB_val kbuf, dbuf; +static MDB_val k0buf; #ifdef _WIN32 #define Z "I" @@ -285,10 +286,15 @@ badend: static void usage(void) { - fprintf(stderr, "usage: %s [-V] [-f input] [-n] [-s name] [-N] [-T] dbpath\n", prog); + fprintf(stderr, "usage: %s [-V] [-a] [-f input] [-n] [-s name] [-N] [-T] dbpath\n", prog); exit(EXIT_FAILURE); } +static int greater(const MDB_val *a, const MDB_val *b) +{ + return 1; +} + int main(int argc, char *argv[]) { int i, rc; @@ -298,7 +304,8 @@ int main(int argc, char *argv[]) MDB_dbi dbi; char *envname; int envflags = 0, putflags = 0; - int dohdr = 0; + int dohdr = 0, append = 0; + MDB_val prevk; prog = argv[0]; @@ -306,19 +313,23 @@ int main(int argc, char *argv[]) usage(); } - /* -f: load file instead of stdin + /* -a: append records in input order + * -f: load file instead of stdin * -n: use NOSUBDIR flag on env_open * -s: load into named subDB * -N: use NOOVERWRITE on puts * -T: read plaintext * -V: print version and exit */ - while ((i = getopt(argc, argv, "f:ns:NTV")) != EOF) { + while ((i = getopt(argc, argv, "af:ns:NTV")) != EOF) { switch(i) { case 'V': printf("%s\n", MDB_VERSION_STRING); exit(0); break; + case 'a': + append = 1; + break; case 'f': if (freopen(optarg, "r", stdin) == NULL) { fprintf(stderr, "%s: %s: reopen: %s\n", @@ -377,12 +388,17 @@ int main(int argc, char *argv[]) } kbuf.mv_size = mdb_env_get_maxkeysize(env) * 2 + 2; - kbuf.mv_data = malloc(kbuf.mv_size); + kbuf.mv_data = malloc(kbuf.mv_size * 2); + k0buf.mv_size = kbuf.mv_size; + k0buf.mv_data = (char *)kbuf.mv_data + kbuf.mv_size; + prevk.mv_size = 0; + prevk.mv_data = k0buf.mv_data; while(!Eof) { MDB_val key, data; int batch = 0; flags = 0; + int appflag; if (!dohdr) { dohdr = 1; @@ -400,6 +416,11 @@ int main(int argc, char *argv[]) fprintf(stderr, "mdb_open failed, error %d %s\n", rc, mdb_strerror(rc)); goto txn_abort; } + if (append) { + mdb_set_compare(txn, dbi, greater); + if (flags & MDB_DUPSORT) + mdb_set_dupsort(txn, dbi, greater); + } rc = mdb_cursor_open(txn, dbi, &mc); if (rc) { @@ -418,7 +439,20 @@ int main(int argc, char *argv[]) goto txn_abort; } - rc = mdb_cursor_put(mc, &key, &data, putflags); + if (append) { + appflag = MDB_APPEND; + if (flags & MDB_DUPSORT) { + if (prevk.mv_size == key.mv_size && !memcmp(prevk.mv_data, key.mv_data, key.mv_size)) + appflag = MDB_APPENDDUP; + else { + memcpy(prevk.mv_data, key.mv_data, key.mv_size); + prevk.mv_size = key.mv_size; + } + } + } else { + appflag = 0; + } + rc = mdb_cursor_put(mc, &key, &data, putflags|appflag); if (rc == MDB_KEYEXIST && putflags) continue; if (rc) { diff --git a/external/easylogging++/easylogging++.cc b/external/easylogging++/easylogging++.cc index 721b2af15..6bc6b2619 100644 --- a/external/easylogging++/easylogging++.cc +++ b/external/easylogging++/easylogging++.cc @@ -1961,8 +1961,13 @@ void VRegistry::setCategories(const char* categories, bool clear) { m_categories.push_back(std::make_pair(ss.str(), level)); }; - if (clear) + if (clear) { m_categories.clear(); + m_categoriesString.clear(); + } + if (!m_categoriesString.empty()) + m_categoriesString += ","; + m_categoriesString += categories; if (!categories) return; @@ -2001,6 +2006,11 @@ void VRegistry::setCategories(const char* categories, bool clear) { } } +std::string VRegistry::getCategories() { + base::threading::ScopedLock scopedLock(lock()); + return m_categoriesString; +} + // Log levels are sorted in a weird way... static int priority(Level level) { if (level == Level::Fatal) return 0; @@ -3073,6 +3083,10 @@ void Loggers::setCategories(const char* categories, bool clear) { ELPP->vRegistry()->setCategories(categories, clear); } +std::string Loggers::getCategories() { + return ELPP->vRegistry()->getCategories(); +} + void Loggers::clearCategories(void) { ELPP->vRegistry()->clearCategories(); } diff --git a/external/easylogging++/easylogging++.h b/external/easylogging++/easylogging++.h index 8f592899e..c55cce755 100644 --- a/external/easylogging++/easylogging++.h +++ b/external/easylogging++/easylogging++.h @@ -2488,6 +2488,8 @@ class VRegistry : base::NoCopy, public base::threading::ThreadSafe { void setCategories(const char* categories, bool clear = true); + std::string getCategories(); + void setModules(const char* modules); bool allowed(Level level, const char* category); @@ -2518,6 +2520,7 @@ class VRegistry : base::NoCopy, public base::threading::ThreadSafe { base::type::EnumType* m_pFlags; std::map<std::string, base::type::VerboseLevel> m_modules; std::deque<std::pair<std::string, Level>> m_categories; + std::string m_categoriesString; std::string m_filenameCommonPrefix; }; } // namespace base @@ -3953,6 +3956,8 @@ class Loggers : base::StaticClass { static void setVModules(const char* modules); /// @brief Sets categories as specified (on the fly) static void setCategories(const char* categories, bool clear = true); + /// @brief Gets current categories + static std::string getCategories(); /// @brief Clears vmodules static void clearVModules(void); /// @brief Clears categories diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3e0bfb59c..57ff28bfc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -102,6 +102,7 @@ monero_add_library(version ${CMAKE_BINARY_DIR}/version.cpp) add_subdirectory(common) add_subdirectory(crypto) add_subdirectory(ringct) +add_subdirectory(checkpoints) add_subdirectory(cryptonote_basic) add_subdirectory(cryptonote_core) if(NOT IOS) diff --git a/src/checkpoints/CMakeLists.txt b/src/checkpoints/CMakeLists.txt new file mode 100644 index 000000000..bc7a27e36 --- /dev/null +++ b/src/checkpoints/CMakeLists.txt @@ -0,0 +1,60 @@ +# Copyright (c) 2014-2017, The Monero Project +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are +# permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list +# of conditions and the following disclaimer in the documentation and/or other +# materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be +# used to endorse or promote products derived from this software without specific +# prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if(APPLE) + find_library(IOKIT_LIBRARY IOKit) + mark_as_advanced(IOKIT_LIBRARY) + list(APPEND EXTRA_LIBRARIES ${IOKIT_LIBRARY}) +endif() + +set(checkpoints_sources + checkpoints.cpp) + +set(checkpoints_headers) + +set(checkpoints_private_headers + checkpoints.h) + +monero_private_headers(checkpoints + ${checkpoints_private_headers}) +monero_add_library(checkpoints + ${checkpoints_sources} + ${checkpoints_headers} + ${checkpoints_private_headers}) +target_link_libraries(checkpoints + PUBLIC + common + cncrypto + ${Boost_DATE_TIME_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${Boost_SERIALIZATION_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_SYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + PRIVATE + ${EXTRA_LIBRARIES}) diff --git a/src/cryptonote_basic/checkpoints.cpp b/src/checkpoints/checkpoints.cpp index 98e509561..bea392db0 100644 --- a/src/cryptonote_basic/checkpoints.cpp +++ b/src/checkpoints/checkpoints.cpp @@ -36,6 +36,7 @@ using namespace epee; #include "common/dns_utils.h" #include "include_base_utils.h" +#include "storages/portable_storage_template_helper.h" // epee json include #include <sstream> #include <random> @@ -51,7 +52,7 @@ namespace cryptonote //--------------------------------------------------------------------------- bool checkpoints::add_checkpoint(uint64_t height, const std::string& hash_str) { - crypto::hash h = null_hash; + crypto::hash h = crypto::null_hash; bool r = epee::string_tools::parse_tpod_from_hex_string(hash_str, h); CHECK_AND_ASSERT_MES(r, false, "Failed to parse checkpoint hash string into binary representation!"); @@ -135,8 +136,14 @@ namespace cryptonote return true; } - bool checkpoints::init_default_checkpoints() + bool checkpoints::init_default_checkpoints(bool testnet) { + if (testnet) + { + // just use the genesis block on testnet + ADD_CHECKPOINT(0, "48ca7cd3c8de5b6a4d53d2861fbdaedca141553559f9be9520068053cda8430b"); + return true; + } ADD_CHECKPOINT(1, "771fbcd656ec1464d3a02ead5e18644030007a0fc664c0a964d30922821a8148"); ADD_CHECKPOINT(10, "c0e3b387e47042f72d8ccdca88071ff96bff1ac7cde09ae113dbb7ad3fe92381"); ADD_CHECKPOINT(100, "ac3e11ca545e57c49fca2b4e8c48c03c23be047c43e471e1394528b1f9f80b2d"); diff --git a/src/cryptonote_basic/checkpoints.h b/src/checkpoints/checkpoints.h index 3a74d8a69..a643c5790 100644 --- a/src/cryptonote_basic/checkpoints.h +++ b/src/checkpoints/checkpoints.h @@ -31,9 +31,9 @@ #pragma once #include <map> #include <vector> -#include "cryptonote_basic_impl.h" #include "misc_log_ex.h" -#include "storages/portable_storage_template_helper.h" // epee json include +#include "crypto/hash.h" +#include "serialization/keyvalue_serialization.h" #define ADD_CHECKPOINT(h, hash) CHECK_AND_ASSERT(add_checkpoint(h, hash), false); #define JSON_HASH_FILE_NAME "checkpoints.json" @@ -148,10 +148,11 @@ namespace cryptonote /** * @brief loads the default main chain checkpoints + * @param testnet whether to load testnet checkpoints or mainnet * * @return true unless adding a checkpoint fails */ - bool init_default_checkpoints(); + bool init_default_checkpoints(bool testnet); /** * @brief load new checkpoints diff --git a/src/common/dns_utils.cpp b/src/common/dns_utils.cpp index 9c306505e..1310b8bfd 100644 --- a/src/common/dns_utils.cpp +++ b/src/common/dns_utils.cpp @@ -443,19 +443,28 @@ bool load_txt_records_from_dns(std::vector<std::string> &good_records, const std std::uniform_int_distribution<int> dis(0, dns_urls.size() - 1); size_t first_index = dis(gen); - bool avail, valid; + // send all requests in parallel + std::vector<boost::thread> threads(dns_urls.size()); + std::deque<bool> avail(dns_urls.size(), false), valid(dns_urls.size(), false); + for (size_t n = 0; n < dns_urls.size(); ++n) + { + threads[n] = boost::thread([n, dns_urls, &records, &avail, &valid](){ + records[n] = tools::DNSResolver::instance().get_txt_record(dns_urls[n], avail[n], valid[n]); + }); + } + for (size_t n = 0; n < dns_urls.size(); ++n) + threads[n].join(); + size_t cur_index = first_index; do { - std::string url = dns_urls[cur_index]; - - records[cur_index] = tools::DNSResolver::instance().get_txt_record(url, avail, valid); - if (!avail) + const std::string &url = dns_urls[cur_index]; + if (!avail[cur_index]) { records[cur_index].clear(); LOG_PRINT_L2("DNSSEC not available for checkpoint update at URL: " << url << ", skipping."); } - if (!valid) + if (!valid[cur_index]) { records[cur_index].clear(); LOG_PRINT_L2("DNSSEC validation failed for checkpoint update at URL: " << url << ", skipping."); diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index e99b6651f..94f924296 100644 --- a/src/crypto/crypto.h +++ b/src/crypto/crypto.h @@ -31,12 +31,16 @@ #pragma once #include <cstddef> +#include <iostream> #include <boost/thread/mutex.hpp> #include <boost/thread/lock_guard.hpp> +#include <boost/utility/value_init.hpp> #include <vector> #include "common/pod-class.h" #include "generic-ops.h" +#include "hex.h" +#include "span.h" #include "hash.h" namespace crypto { @@ -248,6 +252,24 @@ namespace crypto { const signature *sig) { return check_ring_signature(prefix_hash, image, pubs.data(), pubs.size(), sig); } + + inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) { + epee::to_hex::formatted(o, epee::as_byte_span(v)); return o; + } + inline std::ostream &operator <<(std::ostream &o, const crypto::secret_key &v) { + epee::to_hex::formatted(o, epee::as_byte_span(v)); return o; + } + inline std::ostream &operator <<(std::ostream &o, const crypto::key_derivation &v) { + epee::to_hex::formatted(o, epee::as_byte_span(v)); return o; + } + inline std::ostream &operator <<(std::ostream &o, const crypto::key_image &v) { + epee::to_hex::formatted(o, epee::as_byte_span(v)); return o; + } + inline std::ostream &operator <<(std::ostream &o, const crypto::signature &v) { + epee::to_hex::formatted(o, epee::as_byte_span(v)); return o; + } + + const static crypto::public_key null_pkey = boost::value_initialized<crypto::public_key>(); } CRYPTO_MAKE_HASHABLE(public_key) diff --git a/src/crypto/hash.h b/src/crypto/hash.h index 22991e513..610b4502f 100644 --- a/src/crypto/hash.h +++ b/src/crypto/hash.h @@ -31,9 +31,13 @@ #pragma once #include <stddef.h> +#include <iostream> +#include <boost/utility/value_init.hpp> #include "common/pod-class.h" #include "generic-ops.h" +#include "hex.h" +#include "span.h" namespace crypto { @@ -75,6 +79,15 @@ namespace crypto { tree_hash(reinterpret_cast<const char (*)[HASH_SIZE]>(hashes), count, reinterpret_cast<char *>(&root_hash)); } + inline std::ostream &operator <<(std::ostream &o, const crypto::hash &v) { + epee::to_hex::formatted(o, epee::as_byte_span(v)); return o; + } + inline std::ostream &operator <<(std::ostream &o, const crypto::hash8 &v) { + epee::to_hex::formatted(o, epee::as_byte_span(v)); return o; + } + + const static crypto::hash null_hash = boost::value_initialized<crypto::hash>(); + const static crypto::hash8 null_hash8 = boost::value_initialized<crypto::hash8>(); } CRYPTO_MAKE_HASHABLE(hash) diff --git a/src/cryptonote_basic/CMakeLists.txt b/src/cryptonote_basic/CMakeLists.txt index 1503b277e..750be69f1 100644 --- a/src/cryptonote_basic/CMakeLists.txt +++ b/src/cryptonote_basic/CMakeLists.txt @@ -34,7 +34,6 @@ endif() set(cryptonote_basic_sources account.cpp - checkpoints.cpp cryptonote_basic_impl.cpp cryptonote_format_utils.cpp difficulty.cpp @@ -46,7 +45,6 @@ set(cryptonote_basic_headers) set(cryptonote_basic_private_headers account.h account_boost_serialization.h - checkpoints.h connection_context.h cryptonote_basic.h cryptonote_basic_impl.h @@ -60,7 +58,7 @@ set(cryptonote_basic_private_headers verification_context.h) monero_private_headers(cryptonote_basic - ${crypto_private_headers}) + ${cryptonote_basic_private_headers}) monero_add_library(cryptonote_basic ${cryptonote_basic_sources} ${cryptonote_basic_headers} @@ -69,6 +67,7 @@ target_link_libraries(cryptonote_basic PUBLIC common cncrypto + checkpoints ${Boost_DATE_TIME_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_SERIALIZATION_LIBRARY} diff --git a/src/cryptonote_basic/connection_context.h b/src/cryptonote_basic/connection_context.h index 3283543e2..da4b6512e 100644 --- a/src/cryptonote_basic/connection_context.h +++ b/src/cryptonote_basic/connection_context.h @@ -40,7 +40,7 @@ namespace cryptonote struct cryptonote_connection_context: public epee::net_utils::connection_context_base { cryptonote_connection_context(): m_state(state_before_handshake), m_remote_blockchain_height(0), m_last_response_height(0), - m_last_known_hash(cryptonote::null_hash) {} + m_last_known_hash(crypto::null_hash) {} enum state { diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h index c4adf1fcb..eb03d33b9 100644 --- a/src/cryptonote_basic/cryptonote_basic.h +++ b/src/cryptonote_basic/cryptonote_basic.h @@ -53,11 +53,6 @@ namespace cryptonote { - - const static crypto::hash null_hash = AUTO_VAL_INIT(null_hash); - const static crypto::hash8 null_hash8 = AUTO_VAL_INIT(null_hash8); - const static crypto::public_key null_pkey = AUTO_VAL_INIT(null_pkey); - typedef std::vector<crypto::signature> ring_signature; diff --git a/src/cryptonote_basic/cryptonote_basic_impl.h b/src/cryptonote_basic/cryptonote_basic_impl.h index 7a2259b32..5523846d6 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.h +++ b/src/cryptonote_basic/cryptonote_basic_impl.h @@ -33,8 +33,6 @@ #include "cryptonote_basic.h" #include "crypto/crypto.h" #include "crypto/hash.h" -#include "hex.h" -#include "span.h" namespace cryptonote { @@ -136,26 +134,3 @@ namespace cryptonote { bool parse_hash256(const std::string str_hash, crypto::hash& hash); -namespace crypto { - inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) { - epee::to_hex::formatted(o, epee::as_byte_span(v)); return o; - } - inline std::ostream &operator <<(std::ostream &o, const crypto::secret_key &v) { - epee::to_hex::formatted(o, epee::as_byte_span(v)); return o; - } - inline std::ostream &operator <<(std::ostream &o, const crypto::key_derivation &v) { - epee::to_hex::formatted(o, epee::as_byte_span(v)); return o; - } - inline std::ostream &operator <<(std::ostream &o, const crypto::key_image &v) { - epee::to_hex::formatted(o, epee::as_byte_span(v)); return o; - } - inline std::ostream &operator <<(std::ostream &o, const crypto::signature &v) { - epee::to_hex::formatted(o, epee::as_byte_span(v)); return o; - } - inline std::ostream &operator <<(std::ostream &o, const crypto::hash &v) { - epee::to_hex::formatted(o, epee::as_byte_span(v)); return o; - } - inline std::ostream &operator <<(std::ostream &o, const crypto::hash8 &v) { - epee::to_hex::formatted(o, epee::as_byte_span(v)); return o; - } -} diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index e73f5d778..fc979f288 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -632,7 +632,7 @@ namespace cryptonote // prunable rct if (t.rct_signatures.type == rct::RCTTypeNull) { - hashes[2] = cryptonote::null_hash; + hashes[2] = crypto::null_hash; } else { diff --git a/src/cryptonote_core/CMakeLists.txt b/src/cryptonote_core/CMakeLists.txt index 7b73eebd1..169a38f0a 100644 --- a/src/cryptonote_core/CMakeLists.txt +++ b/src/cryptonote_core/CMakeLists.txt @@ -48,7 +48,7 @@ else() endif() monero_private_headers(cryptonote_core - ${crypto_private_headers}) + ${cryptonote_core_private_headers}) monero_add_library(cryptonote_core ${cryptonote_core_sources} ${cryptonote_core_headers} diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index e1cc7361b..0b09d503c 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -49,7 +49,6 @@ #include "common/boost_serialization_helper.h" #include "warnings.h" #include "crypto/hash.h" -#include "cryptonote_basic/checkpoints.h" #include "cryptonote_core.h" #include "ringct/rctSigs.h" #include "common/perf_timer.h" diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index e2da535cd..00b40d0ad 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -51,7 +51,7 @@ #include "cryptonote_tx_utils.h" #include "cryptonote_basic/verification_context.h" #include "crypto/hash.h" -#include "cryptonote_basic/checkpoints.h" +#include "checkpoints/checkpoints.h" #include "cryptonote_basic/hardfork.h" #include "blockchain_db/blockchain_db.h" diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 7c6dc7153..c1a5ae324 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -45,7 +45,7 @@ using namespace epee; #include "misc_language.h" #include <csignal> #include <p2p/net_node.h> -#include "cryptonote_basic/checkpoints.h" +#include "checkpoints/checkpoints.h" #include "ringct/rctTypes.h" #include "blockchain_db/blockchain_db.h" #include "ringct/rctSigs.h" @@ -183,7 +183,7 @@ namespace cryptonote if (!m_testnet && !m_fakechain) { cryptonote::checkpoints checkpoints; - if (!checkpoints.init_default_checkpoints()) + if (!checkpoints.init_default_checkpoints(m_testnet)) { throw std::runtime_error("Failed to initialize checkpoints"); } @@ -1298,11 +1298,12 @@ namespace cryptonote bool core::check_updates() { static const char software[] = "monero"; - static const char subdir[] = "cli"; // because it can never be simple #ifdef BUILD_TAG static const char buildtag[] = BOOST_PP_STRINGIZE(BUILD_TAG); + static const char subdir[] = "cli"; // because it can never be simple #else static const char buildtag[] = "source"; + static const char subdir[] = "source"; // because it can never be simple #endif if (check_updates_level == UPDATES_DISABLED) diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index d2a7eedf5..19ed57aba 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -309,6 +309,7 @@ namespace cryptonote summary_outs_money += dst_entr.amount; } +#if 0 // sort outs by their public key std::vector<size_t> outs_order(tx.vout.size()); for (size_t n = 0; n < tx.vout.size(); ++n) @@ -320,8 +321,10 @@ namespace cryptonote }); tools::apply_permutation(outs_order, [&] (size_t i0, size_t i1) { std::swap(tx.vout[i0], tx.vout[i1]); - std::swap(amount_keys[i0], amount_keys[i1]); + if (!amount_keys.empty()) + std::swap(amount_keys[i0], amount_keys[i1]); }); +#endif //check money if(summary_outs_money > summary_inputs_money ) diff --git a/src/cryptonote_protocol/block_queue.cpp b/src/cryptonote_protocol/block_queue.cpp index 02a8e3ec2..64dd1fb50 100644 --- a/src/cryptonote_protocol/block_queue.cpp +++ b/src/cryptonote_protocol/block_queue.cpp @@ -340,7 +340,7 @@ size_t block_queue::get_num_filled_spans() const crypto::hash block_queue::get_last_known_hash(const boost::uuids::uuid &connection_id) const { boost::unique_lock<boost::recursive_mutex> lock(mutex); - crypto::hash hash = cryptonote::null_hash; + crypto::hash hash = crypto::null_hash; uint64_t highest_height = 0; for (const auto &span: blocks) { diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index 22cfb2299..58e5fc380 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -1484,7 +1484,7 @@ skip: if (!start_from_current_chain) { // we'll want to start off from where we are on that peer, which may not be added yet - if (context.m_last_known_hash != cryptonote::null_hash && r.block_ids.front() != context.m_last_known_hash) + if (context.m_last_known_hash != crypto::null_hash && r.block_ids.front() != context.m_last_known_hash) r.block_ids.push_front(context.m_last_known_hash); } diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp index d949a57b1..af46453cd 100644 --- a/src/daemon/command_parser_executor.cpp +++ b/src/daemon/command_parser_executor.cpp @@ -125,12 +125,17 @@ bool t_command_parser_executor::print_blockchain_info(const std::vector<std::str bool t_command_parser_executor::set_log_level(const std::vector<std::string>& args) { - if(args.size() != 1) + if(args.size() > 1) { std::cout << "use: set_log [<log_level_number_0-4> | <categories>]" << std::endl; return true; } + if (args.empty()) + { + return m_executor.set_log_categories("+"); + } + uint16_t l = 0; if(epee::string_tools::get_xtype_from_string(l, args[0])) { @@ -334,17 +339,18 @@ bool t_command_parser_executor::set_limit(const std::vector<std::string>& args) if(args.size()==0) { return m_executor.get_limit(); } - int limit; + int64_t limit; try { - limit = std::stoi(args[0]); + limit = std::stoll(args[0]); } - catch(std::invalid_argument& ex) { + catch(const std::invalid_argument& ex) { + std::cout << "failed to parse argument" << std::endl; return false; } - if (limit==-1) limit=128; - limit *= 1024; + if (limit > 0) + limit *= 1024; - return m_executor.set_limit(limit); + return m_executor.set_limit(limit, limit); } bool t_command_parser_executor::set_limit_up(const std::vector<std::string>& args) @@ -353,17 +359,18 @@ bool t_command_parser_executor::set_limit_up(const std::vector<std::string>& arg if(args.size()==0) { return m_executor.get_limit_up(); } - int limit; + int64_t limit; try { - limit = std::stoi(args[0]); + limit = std::stoll(args[0]); } - catch(std::invalid_argument& ex) { + catch(const std::invalid_argument& ex) { + std::cout << "failed to parse argument" << std::endl; return false; } - if (limit==-1) limit=128; - limit *= 1024; + if (limit > 0) + limit *= 1024; - return m_executor.set_limit_up(limit); + return m_executor.set_limit(0, limit); } bool t_command_parser_executor::set_limit_down(const std::vector<std::string>& args) @@ -372,17 +379,18 @@ bool t_command_parser_executor::set_limit_down(const std::vector<std::string>& a if(args.size()==0) { return m_executor.get_limit_down(); } - int limit; + int64_t limit; try { - limit = std::stoi(args[0]); + limit = std::stoll(args[0]); } - catch(std::invalid_argument& ex) { + catch(const std::invalid_argument& ex) { + std::cout << "failed to parse argument" << std::endl; return false; } - if (limit==-1) limit=128; - limit *= 1024; + if (limit > 0) + limit *= 1024; - return m_executor.set_limit_down(limit); + return m_executor.set_limit(limit, 0); } bool t_command_parser_executor::out_peers(const std::vector<std::string>& args) diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h index f301ef14a..6443d9be0 100644 --- a/src/daemon/command_parser_executor.h +++ b/src/daemon/command_parser_executor.h @@ -36,7 +36,7 @@ #pragma once -#include <boost/optional/optional_fwd.hpp> +#include <boost/optional/optional.hpp> #include "daemon/rpc_command_executor.h" #include "common/common_fwd.h" diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp index b9f503c6b..3f1543857 100644 --- a/src/daemon/command_server.cpp +++ b/src/daemon/command_server.cpp @@ -141,7 +141,7 @@ t_command_server::t_command_server( m_command_lookup.set_handler( "set_log" , std::bind(&t_command_parser_executor::set_log_level, &m_parser, p::_1) - , "set_log <level>|<categories> - Change current loglevel, <level> is a number 0-4" + , "set_log <level>|<{+,-,}categories> - Change current log level/categories, <level> is a number 0-4" ); m_command_lookup.set_handler( "diff" diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index 11e3a2252..ef593237c 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -599,7 +599,7 @@ bool t_rpc_command_executor::set_log_categories(const std::string &categories) { } } - tools::success_msg_writer() << "Log categories are now " << categories; + tools::success_msg_writer() << "Log categories are now " << res.categories; return true; } @@ -1130,48 +1130,115 @@ bool t_rpc_command_executor::print_status() bool t_rpc_command_executor::get_limit() { - int limit_down = epee::net_utils::connection_basic::get_rate_down_limit( ); - int limit_up = epee::net_utils::connection_basic::get_rate_up_limit( ); - std::cout << "limit-down is " << limit_down/1024 << " kB/s" << std::endl; - std::cout << "limit-up is " << limit_up/1024 << " kB/s" << std::endl; - return true; + cryptonote::COMMAND_RPC_GET_LIMIT::request req; + cryptonote::COMMAND_RPC_GET_LIMIT::response res; + + std::string failure_message = "Couldn't get limit"; + + if (m_is_rpc) + { + if (!m_rpc_client->rpc_request(req, res, "/get_limit", failure_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_get_limit(req, res) || res.status != CORE_RPC_STATUS_OK) + { + tools::fail_msg_writer() << make_error(failure_message, res.status); + return true; + } + } + + tools::msg_writer() << "limit-down is " << res.limit_down/1024 << " kB/s"; + tools::msg_writer() << "limit-up is " << res.limit_up/1024 << " kB/s"; + return true; } -bool t_rpc_command_executor::set_limit(int limit) +bool t_rpc_command_executor::set_limit(int64_t limit_down, int64_t limit_up) { - epee::net_utils::connection_basic::set_rate_down_limit( limit ); - epee::net_utils::connection_basic::set_rate_up_limit( limit ); - std::cout << "Set limit-down to " << limit/1024 << " kB/s" << std::endl; - std::cout << "Set limit-up to " << limit/1024 << " kB/s" << std::endl; - return true; + cryptonote::COMMAND_RPC_SET_LIMIT::request req; + cryptonote::COMMAND_RPC_SET_LIMIT::response res; + + req.limit_down = limit_down; + req.limit_up = limit_up; + + std::string failure_message = "Couldn't set limit"; + + if (m_is_rpc) + { + if (!m_rpc_client->rpc_request(req, res, "/set_limit", failure_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_set_limit(req, res) || res.status != CORE_RPC_STATUS_OK) + { + tools::fail_msg_writer() << make_error(failure_message, res.status); + return true; + } + } + + tools::msg_writer() << "Set limit-down to " << res.limit_down/1024 << " kB/s"; + tools::msg_writer() << "Set limit-up to " << res.limit_up/1024 << " kB/s"; + return true; } bool t_rpc_command_executor::get_limit_up() { - int limit_up = epee::net_utils::connection_basic::get_rate_up_limit( ); - std::cout << "limit-up is " << limit_up/1024 << " kB/s" << std::endl; - return true; -} + cryptonote::COMMAND_RPC_GET_LIMIT::request req; + cryptonote::COMMAND_RPC_GET_LIMIT::response res; -bool t_rpc_command_executor::set_limit_up(int limit) -{ - epee::net_utils::connection_basic::set_rate_up_limit( limit ); - std::cout << "Set limit-up to " << limit/1024 << " kB/s" << std::endl; - return true; + std::string failure_message = "Couldn't get limit"; + + if (m_is_rpc) + { + if (!m_rpc_client->rpc_request(req, res, "/get_limit", failure_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_get_limit(req, res) || res.status != CORE_RPC_STATUS_OK) + { + tools::fail_msg_writer() << make_error(failure_message, res.status); + return true; + } + } + + tools::msg_writer() << "limit-up is " << res.limit_up/1024 << " kB/s"; + return true; } bool t_rpc_command_executor::get_limit_down() { - int limit_down = epee::net_utils::connection_basic::get_rate_down_limit( ); - std::cout << "limit-down is " << limit_down/1024 << " kB/s" << std::endl; - return true; -} + cryptonote::COMMAND_RPC_GET_LIMIT::request req; + cryptonote::COMMAND_RPC_GET_LIMIT::response res; -bool t_rpc_command_executor::set_limit_down(int limit) -{ - epee::net_utils::connection_basic::set_rate_down_limit( limit ); - std::cout << "Set limit-down to " << limit/1024 << " kB/s" << std::endl; - return true; + std::string failure_message = "Couldn't get limit"; + + if (m_is_rpc) + { + if (!m_rpc_client->rpc_request(req, res, "/get_limit", failure_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_get_limit(req, res) || res.status != CORE_RPC_STATUS_OK) + { + tools::fail_msg_writer() << make_error(failure_message, res.status); + return true; + } + } + + tools::msg_writer() << "limit-down is " << res.limit_down/1024 << " kB/s"; + return true; } bool t_rpc_command_executor::out_peers(uint64_t limit) diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h index fc0b39654..d79707a6f 100644 --- a/src/daemon/rpc_command_executor.h +++ b/src/daemon/rpc_command_executor.h @@ -119,11 +119,7 @@ public: bool get_limit_down(); - bool set_limit(int limit); - - bool set_limit_up(int limit); - - bool set_limit_down(int limit); + bool set_limit(int64_t limit_down, int64_t limit_up); bool out_peers(uint64_t limit); diff --git a/src/p2p/CMakeLists.txt b/src/p2p/CMakeLists.txt index 2e34db5d1..123b0a272 100644 --- a/src/p2p/CMakeLists.txt +++ b/src/p2p/CMakeLists.txt @@ -39,6 +39,7 @@ monero_add_library(p2p ${P2P}) target_link_libraries(p2p PUBLIC epee + version ${UPNP_LIBRARIES} ${Boost_CHRONO_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index f1ca50f76..6162d649b 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -390,7 +390,7 @@ namespace nodetool ip::tcp::endpoint endpoint = *i; if (endpoint.address().is_v4()) { - epee::net_utils::network_address na(new epee::net_utils::ipv4_network_address(boost::asio::detail::socket_ops::host_to_network_long(endpoint.address().to_v4().to_ulong()), endpoint.port())); + epee::net_utils::network_address na{epee::net_utils::ipv4_network_address{boost::asio::detail::socket_ops::host_to_network_long(endpoint.address().to_v4().to_ulong()), endpoint.port()}}; seed_nodes.push_back(na); MINFO("Added seed node: " << na.str()); } @@ -1521,7 +1521,7 @@ namespace nodetool return false; std::string ip = epee::string_tools::get_ip_string_from_int32(actual_ip); std::string port = epee::string_tools::num_to_string_fast(node_data.my_port); - epee::net_utils::network_address address(new epee::net_utils::ipv4_network_address(actual_ip, node_data.my_port)); + epee::net_utils::network_address address{epee::net_utils::ipv4_network_address(actual_ip, node_data.my_port)}; peerid_type pr = node_data.peer_id; bool r = m_net_server.connect_async(ip, port, m_config.m_net_config.ping_connection_timeout, [cb, /*context,*/ address, pr, this]( const typename net_server::t_connection_context& ping_context, @@ -1669,7 +1669,7 @@ namespace nodetool if(arg.node_data.peer_id != m_config.m_peer_id && arg.node_data.my_port) { peerid_type peer_id_l = arg.node_data.peer_id; - uint32_t port_l = arg.node_data.my_port; + uint32_t port_l = arg.node_data.my_port; //try ping to be sure that we can add this peer to peer_list try_ping(arg.node_data, context, [peer_id_l, port_l, context, this]() { @@ -1678,7 +1678,7 @@ namespace nodetool //called only(!) if success pinged, update local peerlist peerlist_entry pe; const epee::net_utils::network_address na = context.m_remote_address; - pe.adr.reset(new epee::net_utils::ipv4_network_address(na.as<epee::net_utils::ipv4_network_address>().ip(), port_l)); + pe.adr = epee::net_utils::ipv4_network_address(na.as<epee::net_utils::ipv4_network_address>().ip(), port_l); time_t last_seen; time(&last_seen); pe.last_seen = static_cast<int64_t>(last_seen); diff --git a/src/p2p/net_peerlist_boost_serialization.h b/src/p2p/net_peerlist_boost_serialization.h index 6ea2d48fd..079524aa1 100644 --- a/src/p2p/net_peerlist_boost_serialization.h +++ b/src/p2p/net_peerlist_boost_serialization.h @@ -31,11 +31,19 @@ #pragma once #include "net/net_utils_base.h" +#include "p2p/p2p_protocol_defs.h" namespace boost { namespace serialization { + template <class T, class Archive> + inline void do_serialize(Archive &a, epee::net_utils::network_address& na, T local) + { + if (typename Archive::is_saving()) local = na.as<T>(); + a & local; + if (!typename Archive::is_saving()) na = local; + } template <class Archive, class ver_type> inline void serialize(Archive &a, epee::net_utils::network_address& na, const ver_type ver) { @@ -46,10 +54,8 @@ namespace boost switch (type) { case epee::net_utils::ipv4_network_address::ID: - if (!typename Archive::is_saving()) - na.reset(new epee::net_utils::ipv4_network_address(0, 0)); - a & na.as<epee::net_utils::ipv4_network_address>(); - break; + do_serialize(a, na, epee::net_utils::ipv4_network_address{0, 0}); + break; default: throw std::runtime_error("Unsupported network address type"); } @@ -57,13 +63,14 @@ namespace boost template <class Archive, class ver_type> inline void serialize(Archive &a, epee::net_utils::ipv4_network_address& na, const ver_type ver) { - a & na.m_ip; - a & na.m_port; + uint32_t ip{na.ip()}; + uint16_t port{na.port()}; + a & ip; + a & port; if (!typename Archive::is_saving()) - na.init_ids(); + na = epee::net_utils::ipv4_network_address{ip, port}; } - template <class Archive, class ver_type> inline void serialize(Archive &a, nodetool::peerlist_entry& pl, const ver_type ver) { diff --git a/src/p2p/p2p_protocol_defs.h b/src/p2p/p2p_protocol_defs.h index f2b2cd1da..d49d83989 100644 --- a/src/p2p/p2p_protocol_defs.h +++ b/src/p2p/p2p_protocol_defs.h @@ -120,7 +120,7 @@ namespace nodetool ss << std::setfill ('0') << std::setw (8) << std::hex << std::noshowbase; for(const peerlist_entry& pe: pl) { - ss << pe.id << "\t" << pe.adr->str() << " \tlast_seen: " << epee::misc_utils::get_time_interval_string(now_time - pe.last_seen) << std::endl; + ss << pe.id << "\t" << pe.adr.str() << " \tlast_seen: " << epee::misc_utils::get_time_interval_string(now_time - pe.last_seen) << std::endl; } return ss.str(); } @@ -216,7 +216,7 @@ namespace nodetool std::list<peerlist_entry_base<network_address_old>> local_peerlist; epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist"); for (const auto &p: local_peerlist) - ((response&)this_ref).local_peerlist_new.push_back(peerlist_entry({new epee::net_utils::ipv4_network_address(p.adr.ip, p.adr.port), p.id, p.last_seen})); + ((response&)this_ref).local_peerlist_new.push_back(peerlist_entry({epee::net_utils::ipv4_network_address(p.adr.ip, p.adr.port), p.id, p.last_seen})); } } END_KV_SERIALIZE_MAP() @@ -275,7 +275,7 @@ namespace nodetool std::list<peerlist_entry_base<network_address_old>> local_peerlist; epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist"); for (const auto &p: local_peerlist) - ((response&)this_ref).local_peerlist_new.push_back(peerlist_entry({new epee::net_utils::ipv4_network_address(p.adr.ip, p.adr.port), p.id, p.last_seen})); + ((response&)this_ref).local_peerlist_new.push_back(peerlist_entry({epee::net_utils::ipv4_network_address(p.adr.ip, p.adr.port), p.id, p.last_seen})); } } END_KV_SERIALIZE_MAP() diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index e814dcc1e..b9678f414 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -831,6 +831,7 @@ namespace cryptonote bool core_rpc_server::on_set_log_categories(const COMMAND_RPC_SET_LOG_CATEGORIES::request& req, COMMAND_RPC_SET_LOG_CATEGORIES::response& res) { mlog_set_log(req.categories.c_str()); + res.categories = mlog_get_categories(); res.status = CORE_RPC_STATUS_OK; return true; } @@ -1394,7 +1395,7 @@ namespace cryptonote } else { - na.reset(new epee::net_utils::ipv4_network_address(i->ip, 0)); + na = epee::net_utils::ipv4_network_address{i->ip, 0}; } if (i->ban) m_p2p.block_host(na, i->seconds); @@ -1533,6 +1534,53 @@ namespace cryptonote return true; } //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_limit(const COMMAND_RPC_GET_LIMIT::request& req, COMMAND_RPC_GET_LIMIT::response& res) + { + res.limit_down = epee::net_utils::connection_basic::get_rate_down_limit(); + res.limit_up = epee::net_utils::connection_basic::get_rate_up_limit(); + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_set_limit(const COMMAND_RPC_SET_LIMIT::request& req, COMMAND_RPC_SET_LIMIT::response& res) + { + // -1 = reset to default + // 0 = do not modify + + if (req.limit_down > 0) + { + epee::net_utils::connection_basic::set_rate_down_limit(req.limit_down); + } + else if (req.limit_down < 0) + { + if (req.limit_down != -1) + { + res.status = CORE_RPC_ERROR_CODE_WRONG_PARAM; + return false; + } + epee::net_utils::connection_basic::set_rate_down_limit(nodetool::default_limit_down * 1024); + } + + if (req.limit_up > 0) + { + epee::net_utils::connection_basic::set_rate_up_limit(req.limit_up); + } + else if (req.limit_up < 0) + { + if (req.limit_up != -1) + { + res.status = CORE_RPC_ERROR_CODE_WRONG_PARAM; + return false; + } + epee::net_utils::connection_basic::set_rate_up_limit(nodetool::default_limit_up * 1024); + } + + res.limit_down = epee::net_utils::connection_basic::get_rate_down_limit(); + res.limit_up = epee::net_utils::connection_basic::get_rate_up_limit(); + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::on_out_peers(const COMMAND_RPC_OUT_PEERS::request& req, COMMAND_RPC_OUT_PEERS::response& res) { // TODO @@ -1571,8 +1619,10 @@ namespace cryptonote static const char software[] = "monero"; #ifdef BUILD_TAG static const char buildtag[] = BOOST_PP_STRINGIZE(BUILD_TAG); + static const char subdir[] = "cli"; #else static const char buildtag[] = "source"; + static const char subdir[] = "source"; #endif if (req.command != "check" && req.command != "download" && req.command != "update") @@ -1595,8 +1645,8 @@ namespace cryptonote } res.update = true; res.version = version; - res.user_uri = tools::get_update_url(software, "cli", buildtag, version, true); - res.auto_uri = tools::get_update_url(software, "cli", buildtag, version, false); + res.user_uri = tools::get_update_url(software, subdir, buildtag, version, true); + res.auto_uri = tools::get_update_url(software, subdir, buildtag, version, false); res.hash = hash; if (req.command == "check") { diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index dbbe07972..73a308a72 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -97,6 +97,8 @@ namespace cryptonote MAP_URI_AUTO_JON2("/get_transaction_pool_stats", on_get_transaction_pool_stats, COMMAND_RPC_GET_TRANSACTION_POOL_STATS) MAP_URI_AUTO_JON2_IF("/stop_daemon", on_stop_daemon, COMMAND_RPC_STOP_DAEMON, !m_restricted) MAP_URI_AUTO_JON2("/getinfo", on_get_info, COMMAND_RPC_GET_INFO) + MAP_URI_AUTO_JON2("/get_limit", on_get_limit, COMMAND_RPC_GET_LIMIT) + MAP_URI_AUTO_JON2_IF("/set_limit", on_set_limit, COMMAND_RPC_SET_LIMIT, !m_restricted) MAP_URI_AUTO_JON2_IF("/out_peers", on_out_peers, COMMAND_RPC_OUT_PEERS, !m_restricted) MAP_URI_AUTO_JON2_IF("/start_save_graph", on_start_save_graph, COMMAND_RPC_START_SAVE_GRAPH, !m_restricted) MAP_URI_AUTO_JON2_IF("/stop_save_graph", on_stop_save_graph, COMMAND_RPC_STOP_SAVE_GRAPH, !m_restricted) @@ -155,6 +157,8 @@ namespace cryptonote bool on_get_transaction_pool_hashes(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response& res); bool on_get_transaction_pool_stats(const COMMAND_RPC_GET_TRANSACTION_POOL_STATS::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_STATS::response& res); bool on_stop_daemon(const COMMAND_RPC_STOP_DAEMON::request& req, COMMAND_RPC_STOP_DAEMON::response& res); + bool on_get_limit(const COMMAND_RPC_GET_LIMIT::request& req, COMMAND_RPC_GET_LIMIT::response& res); + bool on_set_limit(const COMMAND_RPC_SET_LIMIT::request& req, COMMAND_RPC_SET_LIMIT::response& res); bool on_out_peers(const COMMAND_RPC_OUT_PEERS::request& req, COMMAND_RPC_OUT_PEERS::response& res); bool on_start_save_graph(const COMMAND_RPC_START_SAVE_GRAPH::request& req, COMMAND_RPC_START_SAVE_GRAPH::response& res); bool on_stop_save_graph(const COMMAND_RPC_STOP_SAVE_GRAPH::request& req, COMMAND_RPC_STOP_SAVE_GRAPH::response& res); diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 99430bf20..85ac2ca30 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -981,8 +981,11 @@ namespace cryptonote struct response { std::string status; + std::string categories; + BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(status) + KV_SERIALIZE(categories) END_KV_SERIALIZE_MAP() }; }; @@ -1244,6 +1247,55 @@ namespace cryptonote }; }; + struct COMMAND_RPC_GET_LIMIT + { + struct request + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + uint64_t limit_up; + uint64_t limit_down; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(limit_up) + KV_SERIALIZE(limit_down) + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_RPC_SET_LIMIT + { + struct request + { + int64_t limit_down; + int64_t limit_up; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(limit_down) + KV_SERIALIZE(limit_up) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + uint64_t limit_up; + uint64_t limit_down; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(limit_up) + KV_SERIALIZE(limit_down) + END_KV_SERIALIZE_MAP() + }; + }; + struct COMMAND_RPC_OUT_PEERS { struct request diff --git a/src/rpc/daemon_handler.cpp b/src/rpc/daemon_handler.cpp index 53eeb5e76..9a6c61b10 100644 --- a/src/rpc/daemon_handler.cpp +++ b/src/rpc/daemon_handler.cpp @@ -542,7 +542,7 @@ namespace rpc { if (m_core.get_current_blockchain_height() <= req.height) { - res.hash = cryptonote::null_hash; + res.hash = crypto::null_hash; res.status = Message::STATUS_FAILED; res.error_details = "height given is higher than current chain height"; return; diff --git a/src/serialization/json_object.cpp b/src/serialization/json_object.cpp index e35389f9c..a40821d19 100644 --- a/src/serialization/json_object.cpp +++ b/src/serialization/json_object.cpp @@ -776,6 +776,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::tx_in_pool& tx) GET_FROM_JSON_OBJECT(val, tx.receive_time, receive_time); GET_FROM_JSON_OBJECT(val, tx.last_relayed_time, last_relayed_time); GET_FROM_JSON_OBJECT(val, tx.relayed, relayed); + GET_FROM_JSON_OBJECT(val, tx.do_not_relay, do_not_relay); } void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::hard_fork_info& info, rapidjson::Value& val) diff --git a/src/serialization/serialization.h b/src/serialization/serialization.h index 639240820..869f5d10e 100644 --- a/src/serialization/serialization.h +++ b/src/serialization/serialization.h @@ -41,6 +41,7 @@ #pragma once #include <vector> +#include <deque> #include <list> #include <string> #include <boost/type_traits/is_integral.hpp> @@ -198,6 +199,11 @@ inline bool do_serialize(Archive &ar, bool &v) #define PREPARE_CUSTOM_VECTOR_SERIALIZATION(size, vec) \ ::serialization::detail::prepare_custom_vector_serialization(size, vec, typename Archive<W>::is_saving()) +/*! \macro PREPARE_CUSTOM_DEQUE_SERIALIZATION + */ +#define PREPARE_CUSTOM_DEQUE_SERIALIZATION(size, vec) \ + ::serialization::detail::prepare_custom_deque_serialization(size, vec, typename Archive<W>::is_saving()) + /*! \macro END_SERIALIZE * \brief self-explanatory */ @@ -292,6 +298,17 @@ namespace serialization { vec.resize(size); } + template <typename T> + void prepare_custom_deque_serialization(size_t size, std::deque<T>& vec, const boost::mpl::bool_<true>& /*is_saving*/) + { + } + + template <typename T> + void prepare_custom_deque_serialization(size_t size, std::deque<T>& vec, const boost::mpl::bool_<false>& /*is_saving*/) + { + vec.resize(size); + } + /*! \fn do_check_stream_state * * \brief self explanatory diff --git a/src/serialization/vector.h b/src/serialization/vector.h index 598cfb92e..12fd59558 100644 --- a/src/serialization/vector.h +++ b/src/serialization/vector.h @@ -37,6 +37,11 @@ bool do_serialize(Archive<false> &ar, std::vector<T> &v); template <template <bool> class Archive, class T> bool do_serialize(Archive<true> &ar, std::vector<T> &v); +template <template <bool> class Archive, class T> +bool do_serialize(Archive<false> &ar, std::deque<T> &v); +template <template <bool> class Archive, class T> +bool do_serialize(Archive<true> &ar, std::deque<T> &v); + namespace serialization { namespace detail @@ -64,7 +69,7 @@ namespace serialization } template <template <bool> class Archive, class T> -bool do_serialize(Archive<false> &ar, std::vector<T> &v) +bool do_serialize_vd(Archive<false> &ar, T &v) { size_t cnt; ar.begin_array(cnt); @@ -93,7 +98,7 @@ bool do_serialize(Archive<false> &ar, std::vector<T> &v) } template <template <bool> class Archive, class T> -bool do_serialize(Archive<true> &ar, std::vector<T> &v) +bool do_serialize_vd(Archive<true> &ar, T &v) { size_t cnt = v.size(); ar.begin_array(cnt); @@ -110,3 +115,13 @@ bool do_serialize(Archive<true> &ar, std::vector<T> &v) ar.end_array(); return true; } + +template <template <bool> class Archive, class T> +bool do_serialize(Archive<false> &ar, std::vector<T> &v) { return do_serialize_vd(ar, v); } +template <template <bool> class Archive, class T> +bool do_serialize(Archive<true> &ar, std::vector<T> &v) { return do_serialize_vd(ar, v); } + +template <template <bool> class Archive, class T> +bool do_serialize(Archive<false> &ar, std::deque<T> &v) { return do_serialize_vd(ar, v); } +template <template <bool> class Archive, class T> +bool do_serialize(Archive<true> &ar, std::deque<T> &v) { return do_serialize_vd(ar, v); } diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index d625634c8..314670327 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -735,6 +735,24 @@ bool simple_wallet::set_confirm_backlog(const std::vector<std::string> &args/* = return true; } +bool simple_wallet::set_confirm_backlog_threshold(const std::vector<std::string> &args/* = std::vector<std::string>()*/) +{ + uint32_t threshold; + if (!string_tools::get_xtype_from_string(threshold, args[1])) + { + fail_msg_writer() << tr("invalid count: must be an unsigned integer"); + return true; + } + + const auto pwd_container = get_and_verify_password(); + if (pwd_container) + { + m_wallet->set_confirm_backlog_threshold(threshold); + m_wallet->rewrite(m_wallet_file, pwd_container->password()); + } + return true; +} + bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<std::string>()*/) { success_msg_writer() << get_commands_str(); @@ -766,7 +784,7 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("donate", boost::bind(&simple_wallet::donate, this, _1), tr("donate [<ring_size>] <amount> [payment_id] - Donate <amount> to the development team (donate.getmonero.org)")); m_cmd_binder.set_handler("sign_transfer", boost::bind(&simple_wallet::sign_transfer, this, _1), tr("Sign a transaction from a file")); m_cmd_binder.set_handler("submit_transfer", boost::bind(&simple_wallet::submit_transfer, this, _1), tr("Submit a signed transaction from a file")); - m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this, _1), tr("set_log <level>|<categories> - Change current log detail (level must be <0-4>)")); + m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this, _1), tr("set_log <level>|{+,-,}<categories> - Change current log detail (level must be <0-4>)")); m_cmd_binder.set_handler("address", boost::bind(&simple_wallet::print_address, this, _1), tr("Show current wallet public address")); m_cmd_binder.set_handler("integrated_address", boost::bind(&simple_wallet::print_integrated_address, this, _1), tr("integrated_address [PID] - Encode a payment ID into an integrated address for the current wallet public address (no argument uses a random payment ID), or decode an integrated address to standard address and payment ID")); m_cmd_binder.set_handler("address_book", boost::bind(&simple_wallet::address_book, this, _1), tr("address_book [(add (<address> [pid <long or short payment id>])|<integrated address> [<description possibly with whitespaces>])|(delete <index>)] - Print all entries in the address book, optionally adding/deleting an entry to/from it")); @@ -775,7 +793,7 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("viewkey", boost::bind(&simple_wallet::viewkey, this, _1), tr("Display private view key")); m_cmd_binder.set_handler("spendkey", boost::bind(&simple_wallet::spendkey, this, _1), tr("Display private spend key")); m_cmd_binder.set_handler("seed", boost::bind(&simple_wallet::seed, this, _1), tr("Display Electrum-style mnemonic seed")); - m_cmd_binder.set_handler("set", boost::bind(&simple_wallet::set_variable, this, _1), tr("Available options: seed language - set wallet seed language; always-confirm-transfers <1|0> - whether to confirm unsplit txes; print-ring-members <1|0> - whether to print detailed information about ring members during confirmation; store-tx-info <1|0> - whether to store outgoing tx info (destination address, payment ID, tx secret key) for future reference; default-ring-size <n> - set default ring size (default is 5); auto-refresh <1|0> - whether to automatically sync new blocks from the daemon; refresh-type <full|optimize-coinbase|no-coinbase|default> - set wallet refresh behaviour; priority [0|1|2|3|4] - default/unimportant/normal/elevated/priority fee; confirm-missing-payment-id <1|0>; ask-password <1|0>; unit <monero|millinero|micronero|nanonero|piconero> - set default monero (sub-)unit; min-outputs-count [n] - try to keep at least that many outputs of value at least min-outputs-value; min-outputs-value [n] - try to keep at least min-outputs-count outputs of at least that value; merge-destinations <1|0> - whether to merge multiple payments to the same destination address; confirm-backlog <1|0> - whether to warn if there is transaction backlog")); + m_cmd_binder.set_handler("set", boost::bind(&simple_wallet::set_variable, this, _1), tr("Available options: seed language - set wallet seed language; always-confirm-transfers <1|0> - whether to confirm unsplit txes; print-ring-members <1|0> - whether to print detailed information about ring members during confirmation; store-tx-info <1|0> - whether to store outgoing tx info (destination address, payment ID, tx secret key) for future reference; default-ring-size <n> - set default ring size (default is 5); auto-refresh <1|0> - whether to automatically sync new blocks from the daemon; refresh-type <full|optimize-coinbase|no-coinbase|default> - set wallet refresh behaviour; priority [0|1|2|3|4] - default/unimportant/normal/elevated/priority fee; confirm-missing-payment-id <1|0>; ask-password <1|0>; unit <monero|millinero|micronero|nanonero|piconero> - set default monero (sub-)unit; min-outputs-count [n] - try to keep at least that many outputs of value at least min-outputs-value; min-outputs-value [n] - try to keep at least min-outputs-count outputs of at least that value; merge-destinations <1|0> - whether to merge multiple payments to the same destination address; confirm-backlog <1|0> - whether to warn if there is transaction backlog; confirm-backlog-threshold [n] - sets a threshold for confirm-backlog to only warn if the transaction backlog is greater than n blocks")); m_cmd_binder.set_handler("encrypted_seed", boost::bind(&simple_wallet::encrypted_seed, this, _1), tr("Display encrypted Electrum-style mnemonic seed")); m_cmd_binder.set_handler("rescan_spent", boost::bind(&simple_wallet::rescan_spent, this, _1), tr("Rescan blockchain for spent outputs")); m_cmd_binder.set_handler("get_tx_key", boost::bind(&simple_wallet::get_tx_key, this, _1), tr("Get transaction key (r) for a given <txid>")); @@ -821,6 +839,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args) success_msg_writer() << "min-outputs-value = " << cryptonote::print_money(m_wallet->get_min_output_value()); success_msg_writer() << "merge-destinations = " << m_wallet->merge_destinations(); success_msg_writer() << "confirm-backlog = " << m_wallet->confirm_backlog(); + success_msg_writer() << "confirm-backlog-threshold = " << m_wallet->get_confirm_backlog_threshold(); return true; } else @@ -867,6 +886,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args) CHECK_SIMPLE_VARIABLE("min-outputs-value", set_min_output_value, tr("amount")); CHECK_SIMPLE_VARIABLE("merge-destinations", set_merge_destinations, tr("0 or 1")); CHECK_SIMPLE_VARIABLE("confirm-backlog", set_confirm_backlog, tr("0 or 1")); + CHECK_SIMPLE_VARIABLE("confirm-backlog-threshold", set_confirm_backlog_threshold, tr("unsigned integer")); } fail_msg_writer() << tr("set: unrecognized argument(s)"); return true; @@ -875,12 +895,14 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args) //---------------------------------------------------------------------------------------------------- bool simple_wallet::set_log(const std::vector<std::string> &args) { - if(args.size() != 1) + if(args.size() > 1) { fail_msg_writer() << tr("usage: set_log <log_level_number_0-4> | <categories>"); return true; } - mlog_set_log(args[0].c_str()); + if (!args.empty()) + mlog_set_log(args[0].c_str()); + success_msg_writer() << "New log categories: " << mlog_get_categories(); return true; } //---------------------------------------------------------------------------------------------------- @@ -1424,6 +1446,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) } catch (const std::exception &e) { } + if (!m_trusted_daemon) + message_writer() << (boost::format(tr("Warning: using an untrusted daemon at %s, privacy will be lessened")) % m_wallet->get_daemon_address()).str(); + m_http_client.set_server(m_wallet->get_daemon_address(), m_wallet->get_daemon_login()); m_wallet->callback(this); @@ -2562,7 +2587,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri } else { - if (nblocks[0].first > 0) + if (nblocks[0].first > m_wallet->get_confirm_backlog_threshold()) prompt << (boost::format(tr("There is currently a %u block backlog at that fee level. Is this okay? (Y/Yes/N/No)")) % nblocks[0].first).str(); } } @@ -3278,7 +3303,7 @@ bool simple_wallet::accept_loaded_tx(const std::function<size_t()> get_num_txes, std::vector<tx_extra_field> tx_extra_fields; bool has_encrypted_payment_id = false; - crypto::hash8 payment_id8 = cryptonote::null_hash8; + crypto::hash8 payment_id8 = crypto::null_hash8; if (cryptonote::parse_tx_extra(cd.extra, tx_extra_fields)) { tx_extra_nonce extra_nonce; diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 3b29e3ca2..6c6d0cf05 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -122,6 +122,7 @@ namespace cryptonote bool set_min_output_value(const std::vector<std::string> &args = std::vector<std::string>()); bool set_merge_destinations(const std::vector<std::string> &args = std::vector<std::string>()); bool set_confirm_backlog(const std::vector<std::string> &args = std::vector<std::string>()); + bool set_confirm_backlog_threshold(const std::vector<std::string> &args = std::vector<std::string>()); bool help(const std::vector<std::string> &args = std::vector<std::string>()); bool start_mining(const std::vector<std::string> &args); bool stop_mining(const std::vector<std::string> &args); diff --git a/src/version.cpp.in b/src/version.cpp.in index 320a8d58a..d1444f867 100644 --- a/src/version.cpp.in +++ b/src/version.cpp.in @@ -3,6 +3,8 @@ #define DEF_MONERO_RELEASE_NAME "Helium Hydra" #define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG +#include "version.h" + const char* const MONERO_VERSION_TAG = DEF_MONERO_VERSION_TAG; const char* const MONERO_VERSION = DEF_MONERO_VERSION; const char* const MONERO_RELEASE_NAME = DEF_MONERO_RELEASE_NAME; diff --git a/src/wallet/api/address_book.cpp b/src/wallet/api/address_book.cpp index a955cb166..9605047b7 100644 --- a/src/wallet/api/address_book.cpp +++ b/src/wallet/api/address_book.cpp @@ -57,7 +57,7 @@ bool AddressBookImpl::addRow(const std::string &dst_addr , const std::string &pa return false; } - crypto::hash payment_id = cryptonote::null_hash; + crypto::hash payment_id = crypto::null_hash; bool has_long_pid = (payment_id_str.empty())? false : tools::wallet2::parse_long_payment_id(payment_id_str, payment_id); // Short payment id provided @@ -106,7 +106,7 @@ void AddressBookImpl::refresh() for (size_t i = 0; i < rows.size(); ++i) { tools::wallet2::address_book_row * row = &rows.at(i); - std::string payment_id = (row->m_payment_id == cryptonote::null_hash)? "" : epee::string_tools::pod_to_hex(row->m_payment_id); + std::string payment_id = (row->m_payment_id == crypto::null_hash)? "" : epee::string_tools::pod_to_hex(row->m_payment_id); std::string address = cryptonote::get_account_address_as_str(m_wallet->m_wallet->testnet(),row->m_address); // convert the zero padded short payment id to integrated address if (payment_id.length() > 16 && payment_id.substr(16).find_first_not_of('0') == std::string::npos) { diff --git a/src/wallet/api/unsigned_transaction.cpp b/src/wallet/api/unsigned_transaction.cpp index 961bd772a..5105278e4 100644 --- a/src/wallet/api/unsigned_transaction.cpp +++ b/src/wallet/api/unsigned_transaction.cpp @@ -230,13 +230,13 @@ std::vector<std::string> UnsignedTransactionImpl::paymentId() const { std::vector<string> result; for (const auto &utx: m_unsigned_tx_set.txes) { - crypto::hash payment_id = cryptonote::null_hash; + crypto::hash payment_id = crypto::null_hash; cryptonote::tx_extra_nonce extra_nonce; std::vector<cryptonote::tx_extra_field> tx_extra_fields; cryptonote::parse_tx_extra(utx.extra, tx_extra_fields); if (cryptonote::find_tx_extra_field_by_type(tx_extra_fields, extra_nonce)) { - crypto::hash8 payment_id8 = cryptonote::null_hash8; + crypto::hash8 payment_id8 = crypto::null_hash8; if(cryptonote::get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8)) { // We can't decrypt short pid without recipient key. @@ -244,10 +244,10 @@ std::vector<std::string> UnsignedTransactionImpl::paymentId() const } else if (!cryptonote::get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id)) { - payment_id = cryptonote::null_hash; + payment_id = crypto::null_hash; } } - if(payment_id != cryptonote::null_hash) + if(payment_id != crypto::null_hash) result.push_back(epee::string_tools::pod_to_hex(payment_id)); else result.push_back(""); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 986f33073..7121fc14f 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -33,6 +33,7 @@ #include <boost/format.hpp> #include <boost/optional/optional.hpp> #include <boost/utility/value_init.hpp> +#include <boost/algorithm/string/join.hpp> #include "include_base_utils.h" using namespace epee; @@ -430,6 +431,20 @@ static void throw_on_rpc_response_error(const boost::optional<std::string> &stat THROW_WALLET_EXCEPTION_IF(*status != CORE_RPC_STATUS_OK, tools::error::wallet_generic_rpc_error, method, *status); } +std::string strjoin(const std::vector<size_t> &V, const char *sep) +{ + std::stringstream ss; + bool first = true; + for (const auto &v: V) + { + if (!first) + ss << sep; + ss << std::to_string(v); + first = false; + } + return ss.str(); +} + } //namespace namespace tools @@ -513,6 +528,7 @@ std::unique_ptr<wallet2> wallet2::make_dummy(const boost::program_options::varia //---------------------------------------------------------------------------------------------------- bool wallet2::init(std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login, uint64_t upper_transaction_size_limit) { + m_checkpoints.init_default_checkpoints(m_testnet); if(m_http_client.is_connected()) m_http_client.disconnect(); m_is_initialized = true; @@ -591,24 +607,24 @@ void wallet2::set_unspent(size_t idx) td.m_spent_height = 0; } //---------------------------------------------------------------------------------------------------- -void wallet2::check_acc_out_precomp(const crypto::public_key &spend_public_key, const tx_out &o, const crypto::key_derivation &derivation, size_t i, bool &received, uint64_t &money_transfered, bool &error) const +void wallet2::check_acc_out_precomp(const crypto::public_key &spend_public_key, const tx_out &o, const crypto::key_derivation &derivation, size_t i, tx_scan_info_t &tx_scan_info) const { if (o.target.type() != typeid(txout_to_key)) { - error = true; + tx_scan_info.error = true; LOG_ERROR("wrong type id in transaction out"); return; } - received = is_out_to_acc_precomp(spend_public_key, boost::get<txout_to_key>(o.target), derivation, i); - if(received) + tx_scan_info.received = is_out_to_acc_precomp(spend_public_key, boost::get<txout_to_key>(o.target), derivation, i); + if(tx_scan_info.received) { - money_transfered = o.amount; // may be 0 for ringct outputs + tx_scan_info.money_transfered = o.amount; // may be 0 for ringct outputs } else { - money_transfered = 0; + tx_scan_info.money_transfered = 0; } - error = false; + tx_scan_info.error = false; } //---------------------------------------------------------------------------------------------------- static uint64_t decodeRct(const rct::rctSig & rv, const crypto::public_key &pub, const crypto::secret_key &sec, unsigned int i, rct::key & mask) @@ -649,6 +665,22 @@ bool wallet2::wallet_generate_key_image_helper(const cryptonote::account_keys& a return true; } //---------------------------------------------------------------------------------------------------- +void wallet2::scan_output(const cryptonote::account_keys &keys, const cryptonote::transaction &tx, const crypto::public_key &tx_pub_key, size_t i, tx_scan_info_t &tx_scan_info, int &num_vouts_received, uint64_t &tx_money_got_in_outs, std::vector<size_t> &outs) +{ + wallet_generate_key_image_helper(keys, tx_pub_key, i, tx_scan_info.in_ephemeral, tx_scan_info.ki); + THROW_WALLET_EXCEPTION_IF(tx_scan_info.in_ephemeral.pub != boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key, + error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key"); + + outs.push_back(i); + if (tx_scan_info.money_transfered == 0) + { + tx_scan_info.money_transfered = tools::decodeRct(tx.rct_signatures, tx_pub_key, keys.m_view_secret_key, i, tx_scan_info.mask); + } + tx_money_got_in_outs += tx_scan_info.money_transfered; + tx_scan_info.amount = tx_scan_info.money_transfered; + ++num_vouts_received; +} +//---------------------------------------------------------------------------------------------------- void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool) { // In this function, tx (probably) only contains the base information @@ -687,13 +719,9 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote int num_vouts_received = 0; tx_pub_key = pub_key_field.pub_key; bool r = true; - std::deque<cryptonote::keypair> in_ephemeral(tx.vout.size()); - std::deque<crypto::key_image> ki(tx.vout.size()); - std::deque<uint64_t> amount(tx.vout.size()); - std::deque<rct::key> mask(tx.vout.size()); tools::threadpool& tpool = tools::threadpool::getInstance(); tools::threadpool::waiter waiter; - int threads = tpool.get_max_concurrency(); + std::unique_ptr<tx_scan_info_t[]> tx_scan_info{new tx_scan_info_t[tx.vout.size()]}; const cryptonote::account_keys& keys = m_account.get_keys(); crypto::key_derivation derivation; generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation); @@ -703,105 +731,64 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote } else if (miner_tx && m_refresh_type == RefreshOptimizeCoinbase) { - uint64_t money_transfered = 0; - bool error = false, received = false; - check_acc_out_precomp(keys.m_account_address.m_spend_public_key, tx.vout[0], derivation, 0, received, money_transfered, error); - if (error) + check_acc_out_precomp(keys.m_account_address.m_spend_public_key, tx.vout[0], derivation, 0, tx_scan_info[0]); + if (tx_scan_info[0].error) { r = false; } else { // this assumes that the miner tx pays a single address - if (received) + if (tx_scan_info[0].received) { - wallet_generate_key_image_helper(keys, tx_pub_key, 0, in_ephemeral[0], ki[0]); - THROW_WALLET_EXCEPTION_IF(in_ephemeral[0].pub != boost::get<cryptonote::txout_to_key>(tx.vout[0].target).key, - error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key"); - - outs.push_back(0); - if (money_transfered == 0) - { - money_transfered = tools::decodeRct(tx.rct_signatures, pub_key_field.pub_key, keys.m_view_secret_key, 0, mask[0]); - } - amount[0] = money_transfered; - tx_money_got_in_outs = money_transfered; - ++num_vouts_received; + scan_output(keys, tx, tx_pub_key, 0, tx_scan_info[0], num_vouts_received, tx_money_got_in_outs, outs); // process the other outs from that tx - - std::vector<uint64_t> money_transfered(tx.vout.size()); - std::deque<bool> error(tx.vout.size()); - std::deque<bool> received(tx.vout.size()); // the first one was already checked for (size_t i = 1; i < tx.vout.size(); ++i) { tpool.submit(&waiter, boost::bind(&wallet2::check_acc_out_precomp, this, std::cref(keys.m_account_address.m_spend_public_key), std::cref(tx.vout[i]), std::cref(derivation), i, - std::ref(received[i]), std::ref(money_transfered[i]), std::ref(error[i]))); + std::ref(tx_scan_info[i]))); } waiter.wait(); + for (size_t i = 1; i < tx.vout.size(); ++i) { - if (error[i]) + if (tx_scan_info[i].error) { r = false; break; } - if (received[i]) + if (tx_scan_info[i].received) { - wallet_generate_key_image_helper(keys, tx_pub_key, i, in_ephemeral[i], ki[i]); - THROW_WALLET_EXCEPTION_IF(in_ephemeral[i].pub != boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key, - error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key"); - - outs.push_back(i); - if (money_transfered[i] == 0) - { - money_transfered[i] = tools::decodeRct(tx.rct_signatures, pub_key_field.pub_key, keys.m_view_secret_key, i, mask[i]); - } - tx_money_got_in_outs += money_transfered[i]; - amount[i] = money_transfered[i]; - ++num_vouts_received; + scan_output(keys, tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs); } } } } } - else if (tx.vout.size() > 1 && threads > 1) + else if (tx.vout.size() > 1 && tools::threadpool::getInstance().get_max_concurrency() > 1) { tools::threadpool& tpool = tools::threadpool::getInstance(); tools::threadpool::waiter waiter; - std::vector<uint64_t> money_transfered(tx.vout.size()); - std::deque<bool> error(tx.vout.size()); - std::deque<bool> received(tx.vout.size()); for (size_t i = 0; i < tx.vout.size(); ++i) { - tpool.submit(&waiter, boost::bind(&wallet2::check_acc_out_precomp, this, std::cref(keys.m_account_address.m_spend_public_key), std::cref(tx.vout[i]), std::cref(derivation), i, - std::ref(received[i]), std::ref(money_transfered[i]), std::ref(error[i]))); + tpool.submit(&waiter, boost::bind(&wallet2::check_acc_out_precomp, this, std::cref(keys.m_account_address.m_spend_public_key), + std::cref(tx.vout[i]), std::cref(derivation), i, std::ref(tx_scan_info[i]))); } waiter.wait(); - tx_money_got_in_outs = 0; + for (size_t i = 0; i < tx.vout.size(); ++i) { - if (error[i]) + if (tx_scan_info[i].error) { r = false; break; } - if (received[i]) + if (tx_scan_info[i].received) { - wallet_generate_key_image_helper(keys, tx_pub_key, i, in_ephemeral[i], ki[i]); - THROW_WALLET_EXCEPTION_IF(in_ephemeral[i].pub != boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key, - error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key"); - - outs.push_back(i); - if (money_transfered[i] == 0) - { - money_transfered[i] = tools::decodeRct(tx.rct_signatures, pub_key_field.pub_key, keys.m_view_secret_key, i, mask[i]); - } - tx_money_got_in_outs += money_transfered[i]; - amount[i] = money_transfered[i]; - ++num_vouts_received; + scan_output(keys, tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs); } } } @@ -809,31 +796,15 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote { for (size_t i = 0; i < tx.vout.size(); ++i) { - uint64_t money_transfered = 0; - bool error = false, received = false; - check_acc_out_precomp(keys.m_account_address.m_spend_public_key, tx.vout[i], derivation, i, received, money_transfered, error); - if (error) + check_acc_out_precomp(keys.m_account_address.m_spend_public_key, tx.vout[i], derivation, i, tx_scan_info[i]); + if (tx_scan_info[i].error) { r = false; break; } - else + if (tx_scan_info[i].received) { - if (received) - { - wallet_generate_key_image_helper(keys, tx_pub_key, i, in_ephemeral[i], ki[i]); - THROW_WALLET_EXCEPTION_IF(in_ephemeral[i].pub != boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key, - error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key"); - - outs.push_back(i); - if (money_transfered == 0) - { - money_transfered = tools::decodeRct(tx.rct_signatures, pub_key_field.pub_key, keys.m_view_secret_key, i, mask[i]); - } - amount[i] = money_transfered; - tx_money_got_in_outs += money_transfered; - ++num_vouts_received; - } + scan_output(keys, tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs); } } } @@ -855,7 +826,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote THROW_WALLET_EXCEPTION_IF(tx.vout.size() <= o, error::wallet_internal_error, "wrong out in transaction: internal index=" + std::to_string(o) + ", total_outs=" + std::to_string(tx.vout.size())); - auto kit = m_pub_keys.find(in_ephemeral[o].pub); + auto kit = m_pub_keys.find(tx_scan_info[o].in_ephemeral.pub); THROW_WALLET_EXCEPTION_IF(kit != m_pub_keys.end() && kit->second >= m_transfers.size(), error::wallet_internal_error, std::string("Unexpected transfer index from public key: ") + "got " + (kit == m_pub_keys.end() ? "<none>" : boost::lexical_cast<std::string>(kit->second)) @@ -871,14 +842,14 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote td.m_global_output_index = o_indices[o]; td.m_tx = (const cryptonote::transaction_prefix&)tx; td.m_txid = txid; - td.m_key_image = ki[o]; + td.m_key_image = tx_scan_info[o].ki; td.m_key_image_known = !m_watch_only; td.m_amount = tx.vout[o].amount; td.m_pk_index = pk_index - 1; if (td.m_amount == 0) { - td.m_mask = mask[o]; - td.m_amount = amount[o]; + td.m_mask = tx_scan_info[o].mask; + td.m_amount = tx_scan_info[o].amount; td.m_rct = true; } else if (miner_tx && tx.version == 2) @@ -893,7 +864,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote } set_unspent(m_transfers.size()-1); m_key_images[td.m_key_image] = m_transfers.size()-1; - m_pub_keys[in_ephemeral[o].pub] = m_transfers.size()-1; + m_pub_keys[tx_scan_info[o].in_ephemeral.pub] = m_transfers.size()-1; LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid); if (0 != m_callback) m_callback->on_money_received(height, txid, tx, td.m_amount); @@ -926,8 +897,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote td.m_pk_index = pk_index - 1; if (td.m_amount == 0) { - td.m_mask = mask[o]; - td.m_amount = amount[o]; + td.m_mask = tx_scan_info[o].mask; + td.m_amount = tx_scan_info[o].amount; td.m_rct = true; } else if (miner_tx && tx.version == 2) @@ -940,7 +911,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote td.m_mask = rct::identity(); td.m_rct = false; } - THROW_WALLET_EXCEPTION_IF(td.get_public_key() != in_ephemeral[o].pub, error::wallet_internal_error, "Inconsistent public keys"); + THROW_WALLET_EXCEPTION_IF(td.get_public_key() != tx_scan_info[o].in_ephemeral.pub, error::wallet_internal_error, "Inconsistent public keys"); THROW_WALLET_EXCEPTION_IF(td.m_spent, error::wallet_internal_error, "Inconsistent spent status"); LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid); @@ -1142,16 +1113,19 @@ void wallet2::get_short_chain_history(std::list<crypto::hash>& ids) const { size_t i = 0; size_t current_multiplier = 1; - size_t sz = m_blockchain.size(); + size_t sz = m_blockchain.size() - m_blockchain.offset(); if(!sz) + { + ids.push_back(m_blockchain.genesis()); return; + } size_t current_back_offset = 1; - bool genesis_included = false; + bool base_included = false; while(current_back_offset < sz) { - ids.push_back(m_blockchain[sz-current_back_offset]); + ids.push_back(m_blockchain[m_blockchain.offset() + sz-current_back_offset]); if(sz-current_back_offset == 0) - genesis_included = true; + base_included = true; if(i < 10) { ++current_back_offset; @@ -1161,8 +1135,10 @@ void wallet2::get_short_chain_history(std::list<crypto::hash>& ids) const } ++i; } - if(!genesis_included) - ids.push_back(m_blockchain[0]); + if(!base_included) + ids.push_back(m_blockchain[m_blockchain.offset()]); + if(m_blockchain.offset()) + ids.push_back(m_blockchain.genesis()); } //---------------------------------------------------------------------------------------------------- void wallet2::parse_block_round(const cryptonote::blobdata &blob, cryptonote::block &bl, crypto::hash &bl_id, bool &error) const @@ -1247,6 +1223,7 @@ void wallet2::process_blocks(uint64_t start_height, const std::list<cryptonote:: size_t tx_o_indices_idx = 0; THROW_WALLET_EXCEPTION_IF(blocks.size() != o_indices.size(), error::wallet_internal_error, "size mismatch"); + THROW_WALLET_EXCEPTION_IF(!m_blockchain.is_in_bounds(current_index), error::wallet_internal_error, "Index out of bounds of hashchain"); tools::threadpool& tpool = tools::threadpool::getInstance(); int threads = tpool.get_max_concurrency(); @@ -1799,6 +1776,13 @@ bool wallet2::refresh(uint64_t & blocks_fetched, bool& received_money, bool& ok) void wallet2::detach_blockchain(uint64_t height) { LOG_PRINT_L0("Detaching blockchain on height " << height); + + // size 1 2 3 4 5 6 7 8 9 + // block 0 1 2 3 4 5 6 7 8 + // C + THROW_WALLET_EXCEPTION_IF(height <= m_checkpoints.get_max_height() && m_blockchain.size() > m_checkpoints.get_max_height(), + error::wallet_internal_error, "Daemon claims reorg below last checkpoint"); + size_t transfers_detached = 0; for (size_t i = 0; i < m_transfers.size(); ++i) @@ -1829,8 +1813,8 @@ void wallet2::detach_blockchain(uint64_t height) } m_transfers.erase(it, m_transfers.end()); - size_t blocks_detached = m_blockchain.end() - (m_blockchain.begin()+height); - m_blockchain.erase(m_blockchain.begin()+height, m_blockchain.end()); + size_t blocks_detached = m_blockchain.size() - height; + m_blockchain.crop(height); m_local_bc_height -= blocks_detached; for (auto it = m_payments.begin(); it != m_payments.end(); ) @@ -1955,6 +1939,9 @@ bool wallet2::store_keys(const std::string& keys_file_name, const std::string& p value2.SetInt(m_confirm_backlog ? 1 :0); json.AddMember("confirm_backlog", value2, json.GetAllocator()); + value2.SetUint(m_confirm_backlog_threshold); + json.AddMember("confirm_backlog_threshold", value2, json.GetAllocator()); + value2.SetInt(m_testnet ? 1 :0); json.AddMember("testnet", value2, json.GetAllocator()); @@ -2030,6 +2017,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const std::string& pa m_min_output_value = 0; m_merge_destinations = false; m_confirm_backlog = true; + m_confirm_backlog_threshold = 0; } else { @@ -2102,6 +2090,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const std::string& pa m_merge_destinations = field_merge_destinations; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, confirm_backlog, int, Int, false, true); m_confirm_backlog = field_confirm_backlog; + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, confirm_backlog_threshold, uint32_t, Uint, false, 0); + m_confirm_backlog_threshold = field_confirm_backlog_threshold; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, testnet, int, Int, false, m_testnet); // Wallet is being opened with testnet flag, but is saved as a mainnet wallet THROW_WALLET_EXCEPTION_IF(m_testnet && !field_testnet, error::wallet_internal_error, "Mainnet wallet can not be opened as testnet wallet"); @@ -2574,13 +2564,49 @@ void wallet2::load(const std::string& wallet_, const std::string& password) check_genesis(genesis_hash); } + trim_hashchain(); + m_local_bc_height = m_blockchain.size(); } //---------------------------------------------------------------------------------------------------- +void wallet2::trim_hashchain() +{ + uint64_t height = m_checkpoints.get_max_height(); + if (!m_blockchain.empty() && m_blockchain.size() == m_blockchain.offset()) + { + MINFO("Fixing empty hashchain"); + epee::json_rpc::request<cryptonote::COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::request> req = AUTO_VAL_INIT(req); + epee::json_rpc::response<cryptonote::COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response, std::string> res = AUTO_VAL_INIT(res); + m_daemon_rpc_mutex.lock(); + req.jsonrpc = "2.0"; + req.id = epee::serialization::storage_entry(0); + req.method = "getblockheaderbyheight"; + req.params.height = m_blockchain.size() - 1; + bool r = net_utils::invoke_http_json("/json_rpc", req, res, m_http_client, rpc_timeout); + m_daemon_rpc_mutex.unlock(); + if (r && res.result.status == CORE_RPC_STATUS_OK) + { + crypto::hash hash; + epee::string_tools::hex_to_pod(res.result.block_header.hash, hash); + m_blockchain.refill(hash); + } + else + { + MERROR("Failed to request block header from daemon, hash chain may be unable to sync till the wallet is loaded with a usable daemon"); + } + } + if (height > 0 && m_blockchain.size() > height) + { + --height; + MDEBUG("trimming to " << height << ", offset " << m_blockchain.offset()); + m_blockchain.trim(height); + } +} +//---------------------------------------------------------------------------------------------------- void wallet2::check_genesis(const crypto::hash& genesis_hash) const { std::string what("Genesis block mismatch. You probably use wallet without testnet flag with blockchain from test network or vice versa"); - THROW_WALLET_EXCEPTION_IF(genesis_hash != m_blockchain[0], error::wallet_internal_error, what); + THROW_WALLET_EXCEPTION_IF(genesis_hash != m_blockchain.genesis(), error::wallet_internal_error, what); } //---------------------------------------------------------------------------------------------------- std::string wallet2::path() const @@ -2595,6 +2621,8 @@ void wallet2::store() //---------------------------------------------------------------------------------------------------- void wallet2::store_to(const std::string &path, const std::string &password) { + trim_hashchain(); + // if file is the same, we do: // 1. save wallet to the *.new file // 2. remove old wallet file @@ -3103,7 +3131,7 @@ crypto::hash wallet2::get_payment_id(const pending_tx &ptx) const { std::vector<tx_extra_field> tx_extra_fields; if(!parse_tx_extra(ptx.tx.extra, tx_extra_fields)) - return cryptonote::null_hash; + return crypto::null_hash; tx_extra_nonce extra_nonce; crypto::hash payment_id = null_hash; if (find_tx_extra_field_by_type(tx_extra_fields, extra_nonce)) @@ -3118,7 +3146,7 @@ crypto::hash wallet2::get_payment_id(const pending_tx &ptx) const } else if (!get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id)) { - payment_id = cryptonote::null_hash; + payment_id = crypto::null_hash; } } return payment_id; @@ -3167,7 +3195,7 @@ void wallet2::commit_tx(pending_tx& ptx) } txid = get_transaction_hash(ptx.tx); - crypto::hash payment_id = cryptonote::null_hash; + crypto::hash payment_id = crypto::null_hash; std::vector<cryptonote::tx_destination_entry> dests; uint64_t amount_in = 0; if (store_tx_info()) @@ -4351,7 +4379,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp } else { - THROW_WALLET_EXCEPTION_IF(original_output_index > dsts.size(), error::wallet_internal_error, "original_output_index too large"); + THROW_WALLET_EXCEPTION_IF(original_output_index > dsts.size(), error::wallet_internal_error, + std::string("original_output_index too large: ") + std::to_string(original_output_index) + " > " + std::to_string(dsts.size())); if (original_output_index == dsts.size()) dsts.push_back(tx_destination_entry(0,addr)); THROW_WALLET_EXCEPTION_IF(memcmp(&dsts[original_output_index].addr, &addr, sizeof(addr)), error::wallet_internal_error, "Mismatched destination address"); @@ -4450,12 +4479,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp TX &tx = txes.back(); LOG_PRINT_L2("Start of loop with " << unused_transfers_indices.size() << " " << unused_dust_indices.size()); - LOG_PRINT_L2("unused_transfers_indices:"); - for (auto t: unused_transfers_indices) - LOG_PRINT_L2(" " << t); - LOG_PRINT_L2("unused_dust_indices:"); - for (auto t: unused_dust_indices) - LOG_PRINT_L2(" " << t); + LOG_PRINT_L2("unused_transfers_indices: " << strjoin(unused_transfers_indices, " ")); + LOG_PRINT_L2("unused_dust_indices:" << strjoin(unused_dust_indices, " ")); LOG_PRINT_L2("dsts size " << dsts.size() << ", first " << (dsts.empty() ? -1 : dsts[0].amount)); LOG_PRINT_L2("adding_fee " << adding_fee << ", use_rct " << use_rct); @@ -4629,6 +4654,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp { LOG_PRINT_L2("We have more to pay, starting another tx"); txes.push_back(TX()); + original_output_index = 0; } } } @@ -5177,10 +5203,9 @@ crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::walle for (size_t i = 0; i < td.m_tx.vout.size(); ++i) { - uint64_t money_transfered = 0; - bool error = false, received = false; - check_acc_out_precomp(keys.m_account_address.m_spend_public_key, td.m_tx.vout[i], derivation, i, received, money_transfered, error); - if (!error && received) + tx_scan_info_t tx_scan_info; + check_acc_out_precomp(keys.m_account_address.m_spend_public_key, td.m_tx.vout[i], derivation, i, tx_scan_info); + if (!tx_scan_info.error && tx_scan_info.received) return tx_pub_key; } } @@ -5188,7 +5213,7 @@ crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::walle // we found no key yielding an output THROW_WALLET_EXCEPTION_IF(true, error::wallet_internal_error, "Public key yielding at least one output wasn't found in the transaction extra"); - return cryptonote::null_pkey; + return crypto::null_pkey; } bool wallet2::export_key_images(const std::string filename) @@ -5475,18 +5500,17 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag size_t output_index = 0; for (const cryptonote::tx_out& out : spent_tx.vout) { - uint64_t money_transfered = 0; - bool error = false, received = false; - check_acc_out_precomp(keys.m_account_address.m_spend_public_key, out, derivation, output_index, received, money_transfered, error); - THROW_WALLET_EXCEPTION_IF(error, error::wallet_internal_error, "check_acc_out_precomp failed"); - if (received) + tx_scan_info_t tx_scan_info; + check_acc_out_precomp(keys.m_account_address.m_spend_public_key, out, derivation, output_index, tx_scan_info); + THROW_WALLET_EXCEPTION_IF(tx_scan_info.error, error::wallet_internal_error, "check_acc_out_precomp failed"); + if (tx_scan_info.received) { - if (money_transfered == 0) + if (tx_scan_info.money_transfered == 0) { rct::key mask; - money_transfered = tools::decodeRct(spent_tx.rct_signatures, tx_pub_key, keys.m_view_secret_key, output_index, mask); + tx_scan_info.money_transfered = tools::decodeRct(spent_tx.rct_signatures, tx_pub_key, keys.m_view_secret_key, output_index, mask); } - tx_money_got_in_outs += money_transfered; + tx_money_got_in_outs += tx_scan_info.money_transfered; } ++output_index; } @@ -5575,20 +5599,28 @@ void wallet2::import_payments_out(const std::list<std::pair<crypto::hash,wallet2 } } -std::vector<crypto::hash> wallet2::export_blockchain() const +std::tuple<size_t,crypto::hash,std::vector<crypto::hash>> wallet2::export_blockchain() const { - std::vector<crypto::hash> bc; - for (auto const &b : m_blockchain) + std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> bc; + std::get<0>(bc) = m_blockchain.offset(); + std::get<1>(bc) = m_blockchain.empty() ? crypto::null_hash: m_blockchain.genesis(); + for (size_t n = m_blockchain.offset(); n < m_blockchain.size(); ++n) { - bc.push_back(b); + std::get<2>(bc).push_back(m_blockchain[n]); } return bc; } -void wallet2::import_blockchain(const std::vector<crypto::hash> &bc) +void wallet2::import_blockchain(const std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> &bc) { m_blockchain.clear(); - for (auto const &b : bc) + if (std::get<0>(bc)) + { + for (size_t n = std::get<0>(bc); n > 0; ++n) + m_blockchain.push_back(std::get<1>(bc)); + m_blockchain.trim(std::get<0>(bc)); + } + for (auto const &b : std::get<2>(bc)) { m_blockchain.push_back(b); } diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 971e98351..839d07881 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -36,6 +36,7 @@ #include <boost/program_options/variables_map.hpp> #include <boost/serialization/list.hpp> #include <boost/serialization/vector.hpp> +#include <boost/serialization/deque.hpp> #include <atomic> #include "include_base_utils.h" @@ -52,6 +53,7 @@ #include "crypto/hash.h" #include "ringct/rctTypes.h" #include "ringct/rctOps.h" +#include "checkpoints/checkpoints.h" #include "wallet_errors.h" #include "common/password.h" @@ -91,6 +93,38 @@ namespace tools } }; + class hashchain + { + public: + hashchain(): m_genesis(crypto::null_hash), m_offset(0) {} + + size_t size() const { return m_blockchain.size() + m_offset; } + size_t offset() const { return m_offset; } + const crypto::hash &genesis() const { return m_genesis; } + void push_back(const crypto::hash &hash) { if (m_offset == 0 && m_blockchain.empty()) m_genesis = hash; m_blockchain.push_back(hash); } + bool is_in_bounds(size_t idx) const { return idx >= m_offset && idx < size(); } + const crypto::hash &operator[](size_t idx) const { return m_blockchain[idx - m_offset]; } + crypto::hash &operator[](size_t idx) { return m_blockchain[idx - m_offset]; } + void crop(size_t height) { m_blockchain.resize(height - m_offset); } + void clear() { m_offset = 0; m_blockchain.clear(); } + bool empty() const { return m_blockchain.empty() && m_offset == 0; } + void trim(size_t height) { while (height > m_offset+1 && m_blockchain.size() > 1) { m_blockchain.pop_front(); ++m_offset; } m_blockchain.shrink_to_fit(); } + void refill(const crypto::hash &hash) { m_blockchain.push_back(hash); --m_offset; } + + template <class t_archive> + inline void serialize(t_archive &a, const unsigned int ver) + { + a & m_offset; + a & m_genesis; + a & m_blockchain; + } + + private: + size_t m_offset; + crypto::hash m_genesis; + std::deque<crypto::hash> m_blockchain; + }; + class wallet2 { friend class ::Serialization_portability_wallet_Test; @@ -133,6 +167,19 @@ namespace tools wallet2(bool testnet = false, bool restricted = false) : m_run(true), m_callback(0), m_testnet(testnet), m_always_confirm_transfers(true), m_print_ring_members(false), m_store_tx_info(true), m_default_mixin(0), m_default_priority(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0), m_confirm_missing_payment_id(true), m_ask_password(true), m_min_output_count(0), m_min_output_value(0), m_merge_destinations(false), m_confirm_backlog(true), m_is_initialized(false), m_restricted(restricted), is_old_file_format(false), m_node_rpc_proxy(m_http_client, m_daemon_rpc_mutex) {} + struct tx_scan_info_t + { + cryptonote::keypair in_ephemeral; + crypto::key_image ki; + rct::key mask; + uint64_t amount; + uint64_t money_transfered; + bool error; + bool received; + + tx_scan_info_t(): money_transfered(0), error(true), received(false) {} + }; + struct transfer_details { uint64_t m_block_height; @@ -203,7 +250,7 @@ namespace tools uint64_t m_timestamp; uint64_t m_unlock_time; - confirmed_transfer_details(): m_amount_in(0), m_amount_out(0), m_change((uint64_t)-1), m_block_height(0), m_payment_id(cryptonote::null_hash), m_timestamp(0), m_unlock_time(0) {} + confirmed_transfer_details(): m_amount_in(0), m_amount_out(0), m_change((uint64_t)-1), m_block_height(0), m_payment_id(crypto::null_hash), m_timestamp(0), m_unlock_time(0) {} confirmed_transfer_details(const unconfirmed_transfer_details &utd, uint64_t height): m_amount_in(utd.m_amount_in), m_amount_out(utd.m_amount_out), m_change(utd.m_change), m_block_height(height), m_dests(utd.m_dests), m_payment_id(utd.m_payment_id), m_timestamp(utd.m_timestamp), m_unlock_time(utd.m_tx.unlock_time) {} }; @@ -439,7 +486,19 @@ namespace tools uint64_t dummy_refresh_height = 0; // moved to keys file if(ver < 5) return; - a & m_blockchain; + if (ver < 19) + { + std::vector<crypto::hash> blockchain; + a & blockchain; + for (const auto &b: blockchain) + { + m_blockchain.push_back(b); + } + } + else + { + a & m_blockchain; + } a & m_transfers; a & m_account_public_address; a & m_key_images; @@ -541,6 +600,8 @@ namespace tools bool merge_destinations() const { return m_merge_destinations; } bool confirm_backlog() const { return m_confirm_backlog; } void confirm_backlog(bool always) { m_confirm_backlog = always; } + void set_confirm_backlog_threshold(uint32_t threshold) { m_confirm_backlog_threshold = threshold; }; + uint32_t get_confirm_backlog_threshold() const { return m_confirm_backlog_threshold; }; bool get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key) const; @@ -588,8 +649,8 @@ namespace tools payment_container export_payments() const; void import_payments(const payment_container &payments); void import_payments_out(const std::list<std::pair<crypto::hash,wallet2::confirmed_transfer_details>> &confirmed_payments); - std::vector<crypto::hash> export_blockchain() const; - void import_blockchain(const std::vector<crypto::hash> &bc); + std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> export_blockchain() const; + void import_blockchain(const std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> &bc); bool export_key_images(const std::string filename); std::vector<std::pair<crypto::key_image, crypto::signature>> export_key_images() const; uint64_t import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, uint64_t &spent, uint64_t &unspent, bool check_spent = true); @@ -650,7 +711,7 @@ namespace tools bool generate_chacha8_key_from_secret_keys(crypto::chacha8_key &key) const; crypto::hash get_payment_id(const pending_tx &ptx) const; crypto::hash8 get_short_payment_id(const pending_tx &ptx) const; - void check_acc_out_precomp(const crypto::public_key &spend_public_key, const cryptonote::tx_out &o, const crypto::key_derivation &derivation, size_t i, bool &received, uint64_t &money_transfered, bool &error) const; + void check_acc_out_precomp(const crypto::public_key &spend_public_key, const cryptonote::tx_out &o, const crypto::key_derivation &derivation, size_t i, tx_scan_info_t &tx_scan_info) const; void parse_block_round(const cryptonote::blobdata &blob, cryptonote::block &bl, crypto::hash &bl_id, bool &error) const; uint64_t get_upper_transaction_size_limit(); std::vector<uint64_t> get_unspent_amounts_vector(); @@ -664,6 +725,8 @@ namespace tools crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const; bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &unused_dust_indices) const; std::vector<size_t> get_only_rct(const std::vector<size_t> &unused_dust_indices, const std::vector<size_t> &unused_transfers_indices) const; + void scan_output(const cryptonote::account_keys &keys, const cryptonote::transaction &tx, const crypto::public_key &tx_pub_key, size_t i, tx_scan_info_t &tx_scan_info, int &num_vouts_received, uint64_t &tx_money_got_in_outs, std::vector<size_t> &outs); + void trim_hashchain(); cryptonote::account_base m_account; boost::optional<epee::net_utils::http::login> m_daemon_login; @@ -671,12 +734,13 @@ namespace tools std::string m_wallet_file; std::string m_keys_file; epee::net_utils::http::http_simple_client m_http_client; - std::vector<crypto::hash> m_blockchain; + hashchain m_blockchain; std::atomic<uint64_t> m_local_bc_height; //temporary workaround std::unordered_map<crypto::hash, unconfirmed_transfer_details> m_unconfirmed_txs; std::unordered_map<crypto::hash, confirmed_transfer_details> m_confirmed_txs; std::unordered_multimap<crypto::hash, payment_details> m_unconfirmed_payments; std::unordered_map<crypto::hash, crypto::secret_key> m_tx_keys; + cryptonote::checkpoints m_checkpoints; transfer_container m_transfers; payment_container m_payments; @@ -711,12 +775,13 @@ namespace tools uint64_t m_min_output_value; bool m_merge_destinations; bool m_confirm_backlog; + uint32_t m_confirm_backlog_threshold; bool m_is_initialized; NodeRPCProxy m_node_rpc_proxy; std::unordered_set<crypto::hash> m_scanned_pool_txs[2]; }; } -BOOST_CLASS_VERSION(tools::wallet2, 18) +BOOST_CLASS_VERSION(tools::wallet2, 19) BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 7) BOOST_CLASS_VERSION(tools::wallet2::payment_details, 1) BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 6) diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index cb35482bd..46b092376 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -362,7 +362,7 @@ namespace tools //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::validate_transfer(const std::list<wallet_rpc::transfer_destination> destinations, std::string payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, epee::json_rpc::error& er) { - crypto::hash8 integrated_payment_id = cryptonote::null_hash8; + crypto::hash8 integrated_payment_id = crypto::null_hash8; std::string extra_nonce; for (auto it = destinations.begin(); it != destinations.end(); it++) { @@ -395,7 +395,7 @@ namespace tools if (has_payment_id) { - if (!payment_id.empty() || integrated_payment_id != cryptonote::null_hash8) + if (!payment_id.empty() || integrated_payment_id != crypto::null_hash8) { er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID; er.message = "A single payment id is allowed per transaction"; @@ -1485,7 +1485,7 @@ namespace tools cryptonote::account_public_address address; bool has_payment_id; crypto::hash8 payment_id8; - crypto::hash payment_id = cryptonote::null_hash; + crypto::hash payment_id = crypto::null_hash; er.message = ""; if(!get_account_address_from_str_or_url(address, has_payment_id, payment_id8, m_wallet->testnet(), req.address, [&er](const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid)->std::string { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 85763f8b5..a5f5335db 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -30,6 +30,7 @@ # The docs say this only affects grouping in IDEs set(folder "tests") +set(TEST_DATA_DIR "${CMAKE_CURRENT_LIST_DIR}/data") if (WIN32 AND STATIC) add_definitions(-DSTATICLIB) diff --git a/tests/core_proxy/core_proxy.cpp b/tests/core_proxy/core_proxy.cpp index aea810a11..a0be3db96 100644 --- a/tests/core_proxy/core_proxy.cpp +++ b/tests/core_proxy/core_proxy.cpp @@ -255,7 +255,7 @@ void tests::proxy_core::build_short_history(std::list<crypto::hash> &m_history, m_history.push_front(cit->first); size_t n = 1 << m_history.size(); - while (m_hash2blkidx.end() != cit && cryptonote::null_hash != cit->second.blk.prev_id && n > 0) { + while (m_hash2blkidx.end() != cit && crypto::null_hash != cit->second.blk.prev_id && n > 0) { n--; cit = m_hash2blkidx.find(cit->second.blk.prev_id); } @@ -265,7 +265,7 @@ void tests::proxy_core::build_short_history(std::list<crypto::hash> &m_history, bool tests::proxy_core::add_block(const crypto::hash &_id, const crypto::hash &_longhash, const cryptonote::block &_blk, const cryptonote::blobdata &_blob) { size_t height = 0; - if (cryptonote::null_hash != _blk.prev_id) { + if (crypto::null_hash != _blk.prev_id) { std::unordered_map<crypto::hash, tests::block_index>::const_iterator cit = m_hash2blkidx.find(_blk.prev_id); if (m_hash2blkidx.end() == cit) { cerr << "ERROR: can't find previous block with id \"" << _blk.prev_id << "\"" << endl; diff --git a/tests/core_proxy/core_proxy.h b/tests/core_proxy/core_proxy.h index 09ed35b1b..cc35be618 100644 --- a/tests/core_proxy/core_proxy.h +++ b/tests/core_proxy/core_proxy.h @@ -46,7 +46,7 @@ namespace tests cryptonote::blobdata blob; std::list<cryptonote::transaction> txes; - block_index() : height(0), id(cryptonote::null_hash), longhash(cryptonote::null_hash) { } + block_index() : height(0), id(crypto::null_hash), longhash(crypto::null_hash) { } block_index(size_t _height, const crypto::hash &_id, const crypto::hash &_longhash, const cryptonote::block &_blk, const cryptonote::blobdata &_blob, const std::list<cryptonote::transaction> &_txes) : height(_height), id(_id), longhash(_longhash), blk(_blk), blob(_blob), txes(_txes) { } }; diff --git a/tests/core_tests/rct.cpp b/tests/core_tests/rct.cpp index 1bdd48fa1..b546e4407 100644 --- a/tests/core_tests/rct.cpp +++ b/tests/core_tests/rct.cpp @@ -486,7 +486,7 @@ bool gen_rct_tx_pre_rct_altered_extra::generate(std::vector<test_event_entry>& e const uint64_t amount_paid = 10000; bool failed = false; return generate_with(events, out_idx, mixin, amount_paid, false, - NULL, [&failed](transaction &tx) {std::string extra_nonce; crypto::hash pid = cryptonote::null_hash; set_payment_id_to_tx_extra_nonce(extra_nonce, pid); if (!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce)) failed = true; }) && !failed; + NULL, [&failed](transaction &tx) {std::string extra_nonce; crypto::hash pid = crypto::null_hash; set_payment_id_to_tx_extra_nonce(extra_nonce, pid); if (!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce)) failed = true; }) && !failed; } bool gen_rct_tx_rct_altered_extra::generate(std::vector<test_event_entry>& events) const @@ -496,6 +496,6 @@ bool gen_rct_tx_rct_altered_extra::generate(std::vector<test_event_entry>& event const uint64_t amount_paid = 10000; bool failed = false; return generate_with(events, out_idx, mixin, amount_paid, false, - NULL, [&failed](transaction &tx) {std::string extra_nonce; crypto::hash pid = cryptonote::null_hash; set_payment_id_to_tx_extra_nonce(extra_nonce, pid); if (!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce)) failed = true; }) && !failed; + NULL, [&failed](transaction &tx) {std::string extra_nonce; crypto::hash pid = crypto::null_hash; set_payment_id_to_tx_extra_nonce(extra_nonce, pid); if (!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce)) failed = true; }) && !failed; } diff --git a/tests/performance_tests/construct_tx.h b/tests/performance_tests/construct_tx.h index 0610c86ed..90e4cf76e 100644 --- a/tests/performance_tests/construct_tx.h +++ b/tests/performance_tests/construct_tx.h @@ -43,7 +43,7 @@ class test_construct_tx : private multi_tx_test_base<a_in_count> static_assert(0 < a_out_count, "out_count must be greater than 0"); public: - static const size_t loop_count = (a_in_count + a_out_count < 100) ? 100 : 10; + static const size_t loop_count = (a_in_count + a_out_count < 10) ? (a_rct ? 10 : 200) : (a_in_count + a_out_count) < 100 ? (a_rct ? 5 : 25) : 5; static const size_t in_count = a_in_count; static const size_t out_count = a_out_count; static const bool rct = a_rct; diff --git a/tests/performance_tests/derive_secret_key.h b/tests/performance_tests/derive_secret_key.h index 1a2945a77..f97deb974 100644 --- a/tests/performance_tests/derive_secret_key.h +++ b/tests/performance_tests/derive_secret_key.h @@ -38,7 +38,7 @@ class test_derive_secret_key : public single_tx_test_base { public: - static const size_t loop_count = 1000000; + static const size_t loop_count = 10000; bool init() { diff --git a/tests/performance_tests/is_out_to_acc.h b/tests/performance_tests/is_out_to_acc.h index 656815db9..ed8951659 100644 --- a/tests/performance_tests/is_out_to_acc.h +++ b/tests/performance_tests/is_out_to_acc.h @@ -47,3 +47,25 @@ public: return cryptonote::is_out_to_acc(m_bob.get_keys(), tx_out, m_tx_pub_key, 0); } }; + +class test_is_out_to_acc_precomp : public single_tx_test_base +{ +public: + static const size_t loop_count = 1000; + + bool init() + { + if (!single_tx_test_base::init()) + return false; + crypto::generate_key_derivation(m_tx_pub_key, m_bob.get_keys().m_view_secret_key, m_derivation); + return true; + } + bool test() + { + const cryptonote::txout_to_key& tx_out = boost::get<cryptonote::txout_to_key>(m_tx.vout[0].target); + return cryptonote::is_out_to_acc_precomp(m_bob.get_keys().m_account_address.m_spend_public_key, tx_out, m_derivation, 0); + } + +private: + crypto::key_derivation m_derivation; +}; diff --git a/tests/performance_tests/main.cpp b/tests/performance_tests/main.cpp index cc9fe86ef..3c0283eca 100644 --- a/tests/performance_tests/main.cpp +++ b/tests/performance_tests/main.cpp @@ -100,6 +100,7 @@ int main(int argc, char** argv) TEST_PERFORMANCE2(test_check_tx_signature, 100, true); TEST_PERFORMANCE0(test_is_out_to_acc); + TEST_PERFORMANCE0(test_is_out_to_acc_precomp); TEST_PERFORMANCE0(test_generate_key_image_helper); TEST_PERFORMANCE0(test_generate_key_derivation); TEST_PERFORMANCE0(test_generate_key_image); diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index 63abe928d..1dac92bed 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -46,6 +46,7 @@ set(unit_tests_sources epee_utils.cpp fee.cpp get_xtype_from_string.cpp + hashchain.cpp http.cpp main.cpp mnemonics.cpp @@ -99,4 +100,4 @@ endif () add_test( NAME unit_tests - COMMAND unit_tests) + COMMAND unit_tests "${TEST_DATA_DIR}") diff --git a/tests/unit_tests/ban.cpp b/tests/unit_tests/ban.cpp index 7d4daafb3..d15716a42 100644 --- a/tests/unit_tests/ban.cpp +++ b/tests/unit_tests/ban.cpp @@ -33,7 +33,7 @@ #include "p2p/net_node.h" #include "cryptonote_protocol/cryptonote_protocol_handler.h" -#define MAKE_IPV4_ADDRESS(a,b,c,d) new epee::net_utils::ipv4_network_address(MAKE_IP(a,b,c,d),0) +#define MAKE_IPV4_ADDRESS(a,b,c,d) epee::net_utils::ipv4_network_address{MAKE_IP(a,b,c,d),0} namespace cryptonote { class blockchain_storage; @@ -51,7 +51,7 @@ public: bool get_short_chain_history(std::list<crypto::hash>& ids) const { return true; } bool get_stat_info(cryptonote::core_stat_info& st_inf) const {return true;} bool have_block(const crypto::hash& id) const {return true;} - void get_blockchain_top(uint64_t& height, crypto::hash& top_id)const{height=0;top_id=cryptonote::null_hash;} + void get_blockchain_top(uint64_t& height, crypto::hash& top_id)const{height=0;top_id=crypto::null_hash;} bool handle_incoming_tx(const cryptonote::blobdata& tx_blob, cryptonote::tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay) { return true; } bool handle_incoming_txs(const std::list<cryptonote::blobdata>& tx_blob, std::vector<cryptonote::tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay) { return true; } bool handle_incoming_block(const cryptonote::blobdata& block_blob, cryptonote::block_verification_context& bvc, bool update_miner_blocktemplate = true) { return true; } diff --git a/tests/unit_tests/checkpoints.cpp b/tests/unit_tests/checkpoints.cpp index d3c4d3b2b..f6015db2f 100644 --- a/tests/unit_tests/checkpoints.cpp +++ b/tests/unit_tests/checkpoints.cpp @@ -30,7 +30,7 @@ #include "gtest/gtest.h" -#include "cryptonote_basic/checkpoints.cpp" +#include "checkpoints/checkpoints.cpp" using namespace cryptonote; diff --git a/tests/unit_tests/epee_utils.cpp b/tests/unit_tests/epee_utils.cpp index e8ddbe3f5..f6cb0c163 100644 --- a/tests/unit_tests/epee_utils.cpp +++ b/tests/unit_tests/epee_utils.cpp @@ -27,6 +27,7 @@ // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <array> +#include <boost/endian/conversion.hpp> #include <boost/range/algorithm/equal.hpp> #include <boost/range/algorithm_ext/iota.hpp> #include <cstdint> @@ -42,7 +43,11 @@ # include <arpa/inet.h> #endif +#include "boost/archive/portable_binary_iarchive.hpp" +#include "boost/archive/portable_binary_oarchive.hpp" #include "hex.h" +#include "net/net_utils_base.h" +#include "p2p/net_peerlist_boost_serialization.h" #include "span.h" #include "string_tools.h" @@ -100,6 +105,40 @@ namespace boost::range::iota(out, 0); return out; } + + #define CHECK_EQUAL(lhs, rhs) \ + EXPECT_TRUE( lhs == rhs ); \ + EXPECT_TRUE( rhs == lhs ); \ + EXPECT_FALSE( lhs != rhs ); \ + EXPECT_FALSE( rhs != lhs ); \ + EXPECT_FALSE( lhs < rhs ); \ + EXPECT_FALSE( rhs < lhs ); \ + EXPECT_TRUE( lhs <= rhs ); \ + EXPECT_TRUE( rhs <= lhs ); \ + EXPECT_FALSE( lhs > rhs ); \ + EXPECT_FALSE( rhs > lhs ); \ + EXPECT_TRUE( lhs >= rhs ); \ + EXPECT_TRUE( rhs >= lhs ) + + #define CHECK_LESS(lhs, rhs) \ + EXPECT_FALSE( lhs == rhs ); \ + EXPECT_FALSE( rhs == lhs ); \ + EXPECT_TRUE( lhs != rhs ); \ + EXPECT_TRUE( rhs != lhs ); \ + EXPECT_TRUE( lhs < rhs ); \ + EXPECT_FALSE( rhs < lhs ); \ + EXPECT_TRUE( lhs <= rhs ); \ + EXPECT_FALSE( rhs <= lhs ); \ + EXPECT_FALSE( lhs > rhs ); \ + EXPECT_TRUE( rhs > lhs ); \ + EXPECT_FALSE( lhs >= rhs ); \ + EXPECT_TRUE( rhs >= lhs ) + + #ifdef BOOST_LITTLE_ENDIAN + #define CHECK_LESS_ENDIAN(lhs, rhs) CHECK_LESS( rhs , lhs ) + #else + #define CHECK_LESS_ENDIAN(lhs, rhs) CHECK_LESS( lhs , rhs ) + #endif } TEST(Span, Traits) @@ -419,3 +458,195 @@ TEST(StringTools, GetIpInt32) EXPECT_EQ(htonl(0xff0aff00), ip); } +TEST(NetUtils, IPv4NetworkAddress) +{ + const auto ip1 = boost::endian::native_to_big(0x330012FFu); + const auto ip_loopback = boost::endian::native_to_big(0x7F000001u); + const auto ip_local = boost::endian::native_to_big(0x0A000000u); + + epee::net_utils::ipv4_network_address address1{ip1, 65535}; + CHECK_EQUAL(address1, address1); + EXPECT_STREQ("51.0.18.255:65535", address1.str().c_str()); + EXPECT_STREQ("51.0.18.255", address1.host_str().c_str()); + EXPECT_FALSE(address1.is_loopback()); + EXPECT_FALSE(address1.is_local()); + EXPECT_EQ(epee::net_utils::ipv4_network_address::ID, address1.get_type_id()); + EXPECT_EQ(ip1, address1.ip()); + EXPECT_EQ(65535, address1.port()); + EXPECT_TRUE(epee::net_utils::ipv4_network_address{std::move(address1)} == address1); + EXPECT_TRUE(epee::net_utils::ipv4_network_address{address1} == address1); + + const epee::net_utils::ipv4_network_address loopback{ip_loopback, 0}; + CHECK_EQUAL(loopback, loopback); + CHECK_LESS_ENDIAN(address1, loopback); + EXPECT_STREQ("127.0.0.1:0", loopback.str().c_str()); + EXPECT_STREQ("127.0.0.1", loopback.host_str().c_str()); + EXPECT_TRUE(loopback.is_loopback()); + EXPECT_FALSE(loopback.is_local()); + EXPECT_EQ(epee::net_utils::ipv4_network_address::ID, address1.get_type_id()); + EXPECT_EQ(ip_loopback, loopback.ip()); + EXPECT_EQ(0, loopback.port()); + + const epee::net_utils::ipv4_network_address local{ip_local, 8080}; + CHECK_EQUAL(local, local); + CHECK_LESS(local, address1); + CHECK_LESS(local, loopback); + EXPECT_FALSE(local.is_loopback()); + EXPECT_TRUE(local.is_local()); + + epee::net_utils::ipv4_network_address address2{ip1, 55}; + CHECK_EQUAL(address2, address2); + CHECK_LESS_ENDIAN(address2, loopback); + CHECK_LESS(local, address2); + EXPECT_STREQ("51.0.18.255:55", address2.str().c_str()); + EXPECT_STREQ("51.0.18.255", address2.host_str().c_str()); + + + address2 = std::move(address1); + CHECK_EQUAL(address2, address1); + + address2 = local; + CHECK_EQUAL(address2, local); + CHECK_LESS(address2, address1); + + { + std::stringstream stream; + { + boost::archive::portable_binary_oarchive ostream{stream}; + ostream << address1; + } + { + boost::archive::portable_binary_iarchive istream{stream}; + istream >> address2; + } + } + CHECK_EQUAL(address1, address2); + EXPECT_EQ(ip1, address2.ip()); + EXPECT_EQ(65535, address2.port()); +} + +TEST(NetUtils, NetworkAddress) +{ + const auto ip1 = boost::endian::native_to_big(0x330012FFu); + const auto ip_loopback = boost::endian::native_to_big(0x7F000001u); + const auto ip_local = boost::endian::native_to_big(0x0A000000u); + + struct custom_address { + constexpr static bool equal(const custom_address&) noexcept { return false; } + constexpr static bool less(const custom_address&) noexcept { return false; } + constexpr static bool is_same_host(const custom_address&) noexcept { return false; } + constexpr static bool is_loopback() noexcept { return false; } + constexpr static bool is_local() noexcept { return false; } + static std::string str() { return {}; } + static std::string host_str() { return {}; } + constexpr static uint8_t get_type_id() noexcept { return uint8_t(-1); } + }; + + const epee::net_utils::network_address empty; + CHECK_EQUAL(empty, empty); + EXPECT_TRUE(empty.is_same_host(empty)); + EXPECT_STREQ("<none>", empty.str().c_str()); + EXPECT_STREQ("<none>", empty.host_str().c_str()); + EXPECT_FALSE(empty.is_loopback()); + EXPECT_FALSE(empty.is_local()); + EXPECT_EQ(0, empty.get_type_id()); + EXPECT_THROW(empty.as<custom_address>(), std::bad_cast); + + epee::net_utils::network_address address1{ + epee::net_utils::ipv4_network_address{ip1, 65535} + }; + CHECK_EQUAL(address1, address1); + CHECK_EQUAL(epee::net_utils::network_address{address1}, address1); + CHECK_LESS(empty, address1); + EXPECT_TRUE(address1.is_same_host(address1)); + EXPECT_FALSE(empty.is_same_host(address1)); + EXPECT_FALSE(address1.is_same_host(empty)); + EXPECT_STREQ("51.0.18.255:65535", address1.str().c_str()); + EXPECT_STREQ("51.0.18.255", address1.host_str().c_str()); + EXPECT_FALSE(address1.is_loopback()); + EXPECT_FALSE(address1.is_local()); + EXPECT_EQ(epee::net_utils::ipv4_network_address::ID, address1.get_type_id()); + EXPECT_NO_THROW(address1.as<epee::net_utils::ipv4_network_address>()); + EXPECT_THROW(address1.as<custom_address>(), std::bad_cast); + + const epee::net_utils::network_address loopback{ + epee::net_utils::ipv4_network_address{ip_loopback, 0} + }; + CHECK_EQUAL(loopback, loopback); + CHECK_LESS(empty, loopback); + CHECK_LESS_ENDIAN(address1, loopback); + EXPECT_TRUE(loopback.is_same_host(loopback)); + EXPECT_FALSE(loopback.is_same_host(address1)); + EXPECT_FALSE(address1.is_same_host(loopback)); + EXPECT_STREQ("127.0.0.1:0", loopback.str().c_str()); + EXPECT_STREQ("127.0.0.1", loopback.host_str().c_str()); + EXPECT_TRUE(loopback.is_loopback()); + EXPECT_FALSE(loopback.is_local()); + EXPECT_EQ(epee::net_utils::ipv4_network_address::ID, address1.get_type_id()); + + const epee::net_utils::network_address local{ + epee::net_utils::ipv4_network_address{ip_local, 8080} + }; + CHECK_EQUAL(local, local); + CHECK_LESS(local, loopback); + CHECK_LESS(local, address1); + EXPECT_FALSE(local.is_loopback()); + EXPECT_TRUE(local.is_local()); + + epee::net_utils::network_address address2{ + epee::net_utils::ipv4_network_address{ip1, 55} + }; + CHECK_EQUAL(address2, address2); + CHECK_LESS(address2, address1); + CHECK_LESS(local, address2); + CHECK_LESS_ENDIAN(address2, loopback); + EXPECT_TRUE(address1.is_same_host(address2)); + EXPECT_TRUE(address2.is_same_host(address1)); + EXPECT_STREQ("51.0.18.255:55", address2.str().c_str()); + EXPECT_STREQ("51.0.18.255", address2.host_str().c_str()); + + address2 = std::move(address1); + CHECK_EQUAL(address1, address1); + CHECK_EQUAL(empty, address1); + CHECK_LESS(address1, address2); + EXPECT_FALSE(address1.is_same_host(address2)); + EXPECT_FALSE(address2.is_same_host(address1)); + EXPECT_STREQ("51.0.18.255:65535", address2.str().c_str()); + EXPECT_STREQ("51.0.18.255", address2.host_str().c_str()); + EXPECT_FALSE(address1.is_loopback()); + EXPECT_FALSE(address1.is_local()); + EXPECT_THROW(address1.as<epee::net_utils::ipv4_network_address>(), std::bad_cast); + EXPECT_NO_THROW(address2.as<epee::net_utils::ipv4_network_address>()); + + address2 = local; + CHECK_EQUAL(address2, local); + CHECK_LESS(address1, address2); + EXPECT_TRUE(address2.is_same_host(local)); + EXPECT_TRUE(local.is_same_host(address2)); + EXPECT_FALSE(address2.is_same_host(address1)); + EXPECT_FALSE(address1.is_same_host(address2)); + + { + std::stringstream stream; + { + boost::archive::portable_binary_oarchive ostream{stream}; + ostream << address2; + } + { + boost::archive::portable_binary_iarchive istream{stream}; + istream >> address1; + } + } + CHECK_EQUAL(address1, address2); + EXPECT_TRUE(address1.is_same_host(address2)); + EXPECT_TRUE(address2.is_same_host(address1)); + EXPECT_NO_THROW(address1.as<epee::net_utils::ipv4_network_address>()); + + address1 = custom_address{}; + CHECK_EQUAL(address1, address1); + CHECK_LESS(address2, address1); + EXPECT_FALSE(address1.is_same_host(loopback)); + EXPECT_FALSE(loopback.is_same_host(address1)); + EXPECT_THROW(address1.as<epee::net_utils::ipv4_network_address>(), std::bad_cast); + EXPECT_NO_THROW(address1.as<custom_address>()); +} diff --git a/tests/unit_tests/hashchain.cpp b/tests/unit_tests/hashchain.cpp new file mode 100644 index 000000000..0fa0f784a --- /dev/null +++ b/tests/unit_tests/hashchain.cpp @@ -0,0 +1,129 @@ +// Copyright (c) 2014-2017, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// FIXME: move this into a full wallet2 unit test suite, if possible + +#include "gtest/gtest.h" + +#include "wallet/wallet2.h" + +static crypto::hash make_hash(uint64_t n) +{ + union + { + crypto::hash hash; + uint64_t n; + } hash; + hash.hash = crypto::null_hash; + hash.n = n; + return hash.hash; +} + +TEST(hashchain, empty) +{ + tools::hashchain hashchain; + ASSERT_EQ(hashchain.size(), 0); + ASSERT_EQ(hashchain.offset(), 0); +} + +TEST(hashchain, genesis) +{ + tools::hashchain hashchain; + hashchain.push_back(make_hash(1)); + ASSERT_EQ(hashchain.size(), 1); + ASSERT_EQ(hashchain.genesis(), make_hash(1)); + hashchain.push_back(make_hash(2)); + ASSERT_EQ(hashchain.size(), 2); + ASSERT_EQ(hashchain.genesis(), make_hash(1)); +} + +TEST(hashchain, push_back) +{ + tools::hashchain hashchain; + hashchain.push_back(make_hash(1)); + hashchain.push_back(make_hash(2)); + hashchain.push_back(make_hash(3)); + ASSERT_EQ(hashchain[0], make_hash(1)); + ASSERT_EQ(hashchain[1], make_hash(2)); + ASSERT_EQ(hashchain[2], make_hash(3)); +} + +TEST(hashchain, clear_empty) +{ + tools::hashchain hashchain; + ASSERT_TRUE(hashchain.empty()); + hashchain.push_back(make_hash(1)); + ASSERT_FALSE(hashchain.empty()); + hashchain.push_back(make_hash(2)); + ASSERT_FALSE(hashchain.empty()); + hashchain.clear(); + ASSERT_TRUE(hashchain.empty()); +} + +TEST(hashchain, crop) +{ + tools::hashchain hashchain; + hashchain.push_back(make_hash(1)); + hashchain.push_back(make_hash(2)); + hashchain.push_back(make_hash(3)); + ASSERT_EQ(hashchain.size(), 3); + ASSERT_EQ(hashchain[0], make_hash(1)); + ASSERT_EQ(hashchain[1], make_hash(2)); + ASSERT_EQ(hashchain[2], make_hash(3)); + hashchain.crop(3); + ASSERT_EQ(hashchain.size(), 3); + hashchain.crop(2); + ASSERT_EQ(hashchain.size(), 2); + ASSERT_EQ(hashchain[0], make_hash(1)); + ASSERT_EQ(hashchain[1], make_hash(2)); + ASSERT_EQ(hashchain.genesis(), make_hash(1)); + hashchain.crop(0); + ASSERT_TRUE(hashchain.empty()); + ASSERT_EQ(hashchain.size(), 0); + hashchain.push_back(make_hash(5)); + ASSERT_EQ(hashchain.genesis(), make_hash(5)); + ASSERT_EQ(hashchain.size(), 1); +} + +TEST(hashchain, trim) +{ + tools::hashchain hashchain; + hashchain.push_back(make_hash(1)); + hashchain.push_back(make_hash(2)); + hashchain.push_back(make_hash(3)); + ASSERT_EQ(hashchain.offset(), 0); + hashchain.trim(2); + ASSERT_EQ(hashchain.offset(), 2); + ASSERT_EQ(hashchain.size(), 3); + ASSERT_EQ(hashchain[2], make_hash(3)); + hashchain.trim(3); + ASSERT_EQ(hashchain.offset(), 3); + ASSERT_EQ(hashchain.size(), 3); + ASSERT_FALSE(hashchain.empty()); + ASSERT_EQ(hashchain.genesis(), make_hash(1)); +} diff --git a/tests/unit_tests/main.cpp b/tests/unit_tests/main.cpp index b470249a3..b2abad942 100644 --- a/tests/unit_tests/main.cpp +++ b/tests/unit_tests/main.cpp @@ -30,14 +30,32 @@ #include "gtest/gtest.h" +#include <boost/filesystem.hpp> + #include "include_base_utils.h" +#include "unit_tests_utils.h" + +boost::filesystem::path unit_test::data_dir; int main(int argc, char** argv) { - epee::string_tools::set_module_name_and_folder(argv[0]); mlog_configure(mlog_get_default_log_path("unit_tests.log"), true); epee::debug::get_set_enable_assert(true, false); ::testing::InitGoogleTest(&argc, argv); + + // Process remaining arguments + if (argc == 2 && argv[1] != NULL) { // one arg: path to dir with test data + unit_test::data_dir = argv[1]; + } else if (argc == 1) { // legacy: assume test binaries in 'build/release' + epee::string_tools::set_module_name_and_folder(argv[0]); + unit_test::data_dir = boost::filesystem::path(epee::string_tools::get_current_module_folder()) + .parent_path().parent_path().parent_path().parent_path() + .append("tests").append("data"); + } else { + std::cerr << "Usage: " << argv[0] << " [<path-to-test-data-dir>]" << std::endl; + return 1; + } + return RUN_ALL_TESTS(); } diff --git a/tests/unit_tests/output_selection.cpp b/tests/unit_tests/output_selection.cpp index ed436dffd..6ff73b107 100644 --- a/tests/unit_tests/output_selection.cpp +++ b/tests/unit_tests/output_selection.cpp @@ -42,7 +42,7 @@ static tools::wallet2::transfer_container make_transfers_container(size_t N) tools::wallet2::transfer_details &td = transfers.back(); td.m_block_height = 1000; td.m_spent = false; - td.m_txid = cryptonote::null_hash; + td.m_txid = crypto::null_hash; td.m_txid.data[0] = n & 0xff; td.m_txid.data[1] = (n >> 8) & 0xff; td.m_txid.data[2] = (n >> 16) & 0xff; diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp index 6f9fe7d11..e701a53ce 100644 --- a/tests/unit_tests/serialization.cpp +++ b/tests/unit_tests/serialization.cpp @@ -47,6 +47,7 @@ #include "serialization/binary_utils.h" #include "wallet/wallet2.h" #include "gtest/gtest.h" +#include "unit_tests_utils.h" using namespace std; struct Struct @@ -671,12 +672,12 @@ TEST(Serialization, portability_wallet) const bool testnet = true; const bool restricted = false; tools::wallet2 w(testnet, restricted); - string wallet_file = epee::string_tools::get_current_module_folder() + "/../../../../tests/data/wallet_9svHk1"; + const boost::filesystem::path wallet_file = unit_test::data_dir / "wallet_9svHk1"; string password = "test"; bool r = false; try { - w.load(wallet_file, password); + w.load(wallet_file.native(), password); r = true; } catch (const exception& e) @@ -791,9 +792,9 @@ TEST(Serialization, portability_wallet) TEST(Serialization, portability_outputs) { // read file - const std::string filename = epee::string_tools::get_current_module_folder() + "/../../../../tests/data/outputs"; + const boost::filesystem::path filename = unit_test::data_dir / "outputs"; std::string data; - bool r = epee::file_io_utils::load_file_to_string(filename, data); + bool r = epee::file_io_utils::load_file_to_string(filename.native(), data); ASSERT_TRUE(r); const size_t magiclen = strlen(OUTPUT_EXPORT_FILE_MAGIC); ASSERT_FALSE(data.size() < magiclen || memcmp(data.data(), OUTPUT_EXPORT_FILE_MAGIC, magiclen)); @@ -906,10 +907,10 @@ TEST(Serialization, portability_outputs) #define UNSIGNED_TX_PREFIX "Monero unsigned tx set\003" TEST(Serialization, portability_unsigned_tx) { - const string filename = epee::string_tools::get_current_module_folder() + "/../../../../tests/data/unsigned_monero_tx"; + const boost::filesystem::path filename = unit_test::data_dir / "unsigned_monero_tx"; std::string s; const bool testnet = true; - bool r = epee::file_io_utils::load_file_to_string(filename, s); + bool r = epee::file_io_utils::load_file_to_string(filename.native(), s); ASSERT_TRUE(r); const size_t magiclen = strlen(UNSIGNED_TX_PREFIX); ASSERT_FALSE(strncmp(s.c_str(), UNSIGNED_TX_PREFIX, magiclen)); @@ -1054,10 +1055,10 @@ TEST(Serialization, portability_unsigned_tx) #define SIGNED_TX_PREFIX "Monero signed tx set\003" TEST(Serialization, portability_signed_tx) { - const string filename = epee::string_tools::get_current_module_folder() + "/../../../../tests/data/signed_monero_tx"; + const boost::filesystem::path filename = unit_test::data_dir / "signed_monero_tx"; const bool testnet = true; std::string s; - bool r = epee::file_io_utils::load_file_to_string(filename, s); + bool r = epee::file_io_utils::load_file_to_string(filename.native(), s); ASSERT_TRUE(r); const size_t magiclen = strlen(SIGNED_TX_PREFIX); ASSERT_FALSE(strncmp(s.c_str(), SIGNED_TX_PREFIX, magiclen)); diff --git a/tests/unit_tests/test_peerlist.cpp b/tests/unit_tests/test_peerlist.cpp index 4a546b50d..849020d25 100644 --- a/tests/unit_tests/test_peerlist.cpp +++ b/tests/unit_tests/test_peerlist.cpp @@ -38,7 +38,7 @@ TEST(peer_list, peer_list_general) { nodetool::peerlist_manager plm; plm.init(false); -#define MAKE_IPV4_ADDRESS(a,b,c,d,e) new epee::net_utils::ipv4_network_address(MAKE_IP(a,b,c,d),e) +#define MAKE_IPV4_ADDRESS(a,b,c,d,e) epee::net_utils::ipv4_network_address{MAKE_IP(a,b,c,d),e} #define ADD_GRAY_NODE(addr_, id_, last_seen_) { nodetool::peerlist_entry ple; ple.last_seen=last_seen_;ple.adr = addr_; ple.id = id_;plm.append_with_peer_gray(ple);} #define ADD_WHITE_NODE(addr_, id_, last_seen_) { nodetool::peerlist_entry ple;ple.last_seen=last_seen_; ple.adr = addr_; ple.id = id_;plm.append_with_peer_white(ple);} diff --git a/tests/unit_tests/test_tx_utils.cpp b/tests/unit_tests/test_tx_utils.cpp index 0ff91c247..4ce62e2f5 100644 --- a/tests/unit_tests/test_tx_utils.cpp +++ b/tests/unit_tests/test_tx_utils.cpp @@ -141,7 +141,7 @@ TEST(parse_and_validate_tx_extra, is_valid_tx_extra_parsed) cryptonote::blobdata b = "dsdsdfsdfsf"; ASSERT_TRUE(cryptonote::construct_miner_tx(0, 0, 10000000000000, 1000, TEST_FEE, acc.get_keys().m_account_address, tx, b, 1)); crypto::public_key tx_pub_key = cryptonote::get_tx_pub_key_from_extra(tx); - ASSERT_NE(tx_pub_key, cryptonote::null_pkey); + ASSERT_NE(tx_pub_key, crypto::null_pkey); } TEST(parse_and_validate_tx_extra, fails_on_big_extra_nonce) { diff --git a/tests/unit_tests/unit_tests_utils.h b/tests/unit_tests/unit_tests_utils.h index 11230c0db..a07eaf02b 100644 --- a/tests/unit_tests/unit_tests_utils.h +++ b/tests/unit_tests/unit_tests_utils.h @@ -31,9 +31,12 @@ #pragma once #include <atomic> +#include <boost/filesystem.hpp> namespace unit_test { + extern boost::filesystem::path data_dir; + class call_counter { public: diff --git a/translations/monero_it.ts b/translations/monero_it.ts index c30413219..10c1599df 100644 --- a/translations/monero_it.ts +++ b/translations/monero_it.ts @@ -6,17 +6,17 @@ <message> <location filename="../src/wallet/api/address_book.cpp" line="55"/> <source>Invalid destination address</source> - <translation>Indirizzo destinatario invalido</translation> + <translation>Indirizzo destinatario non valido</translation> </message> <message> <location filename="../src/wallet/api/address_book.cpp" line="65"/> <source>Invalid payment ID. Short payment ID should only be used in an integrated address</source> - <translation>ID pagamento invalido. Il pagamento id corto dovrebbe essere usato solo in un indirizzo integrato</translation> + <translation>ID pagamento non valido. Il pagamento ID corto dovrebbe essere usato solo in un indirizzo integrato</translation> </message> <message> <location filename="../src/wallet/api/address_book.cpp" line="72"/> <source>Invalid payment ID</source> - <translation>ID pagamento invalido</translation> + <translation>ID pagamento non valido</translation> </message> <message> <location filename="../src/wallet/api/address_book.cpp" line="79"/> @@ -54,7 +54,7 @@ <message> <location filename="../src/wallet/api/pending_transaction.cpp" line="126"/> <source>. Reason: </source> - <translation>Motivo: </translation> + <translation>. Motivo: </translation> </message> <message> <location filename="../src/wallet/api/pending_transaction.cpp" line="128"/> @@ -93,12 +93,12 @@ <message> <location filename="../src/wallet/api/unsigned_transaction.cpp" line="151"/> <source>Change goes to more than one address</source> - <translation>Il cambiamento ha effetto su più di un in indirizzo</translation> + <translation>Il cambiamento ha effetto su più di un indirizzo</translation> </message> <message> <location filename="../src/wallet/api/unsigned_transaction.cpp" line="164"/> <source>sending %s to %s</source> - <translation>Inviando %s a %s</translation> + <translation>inviando %s a %s</translation> </message> <message> <location filename="../src/wallet/api/unsigned_transaction.cpp" line="170"/> @@ -113,12 +113,12 @@ <message> <location filename="../src/wallet/api/unsigned_transaction.cpp" line="179"/> <source>no change</source> - <translation>nessun cambiamento</translation> + <translation>nessuna modifica</translation> </message> <message> <location filename="../src/wallet/api/unsigned_transaction.cpp" line="181"/> <source>Loaded %lu transactions, for %s, fee %s, %s, %s, with min mixin %lu. %s</source> - <translation>Caricato %lu transazioni, per %s, tassa %s, %s, %s, %s, con mixin %lu. %s</translation> + <translation>Caricato %lu transazioni, per %s, commissione %s, %s, %s, %s, con mixin %lu. %s</translation> </message> </context> <context> @@ -154,53 +154,53 @@ <message> <location filename="../src/wallet/api/wallet.cpp" line="1081"/> <source>failed to get random outputs to mix</source> - <translation>Impossibile raccogliere outputs random da mixare</translation> + <translation>impossibile recuperare outputs random da mixare</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="994"/> <location filename="../src/wallet/api/wallet.cpp" line="1088"/> <source>not enough money to transfer, available only %s, sent amount %s</source> - <translation>non hai abbastanza soldi da trasferire, sono disponibili solo %s, ammontare inviato %s</translation> + <translation>non hai abbastanza fondi da trasferire, sono disponibili solo %s, ammontare inviato %s</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="403"/> <source>failed to parse address</source> - <translation>Analisi(parse) indirizzo fallita</translation> + <translation>parsing indirizzo fallito</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="415"/> <source>failed to parse secret spend key</source> - <translation>Impossibile analizzare(parse) la chiave segreta spendibile</translation> + <translation>impossibile fare il parsing della chiave segreta di spesa</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="425"/> <source>No view key supplied, cancelled</source> - <translation>Non è stata fornita nessuna chiave per visualizzazione</translation> + <translation>Non è stata fornita nessuna chiave di visualizzazione</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="432"/> <source>failed to parse secret view key</source> - <translation>Impossibile analizzare(parse) la chiave segreta per visualizzazione</translation> + <translation>impossibile fare il parsing della chiave segreta di visualizzazione</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="442"/> <source>failed to verify secret spend key</source> - <translation>impossibile verificare chiave segreta spendibile</translation> + <translation>impossibile verificare chiave segreta di spesa</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="447"/> <source>spend key does not match address</source> - <translation>la chiave spendibile non corrisponde all'indirizzo</translation> + <translation>la chiave di spesa non corrisponde all'indirizzo</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="453"/> <source>failed to verify secret view key</source> - <translation>verifica chiave segreta per visualizzazione fallita</translation> + <translation>verifica chiave segreta di visualizzazione fallita</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="458"/> <source>view key does not match address</source> - <translation>La chiave per visualizzazione non corrisponde all'indirizzo</translation> + <translation>la chiave di visualizzazione non corrisponde all'indirizzo</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="477"/> @@ -241,7 +241,7 @@ <location filename="../src/wallet/api/wallet.cpp" line="1003"/> <location filename="../src/wallet/api/wallet.cpp" line="1097"/> <source>not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)</source> - <translation>Non hai abbastanza ssoldi da trasferire, disponibili solo %s, ammontare transazione %s = %s + %s (tassa)</translation> + <translation>non hai abbastanza fondi da trasferire, disponibili solo %s, ammontare transazione %s = %s + %s (commissione)</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="1012"/> @@ -301,7 +301,7 @@ <location filename="../src/wallet/api/wallet.cpp" line="1042"/> <location filename="../src/wallet/api/wallet.cpp" line="1136"/> <source>unexpected error: </source> - <translation>errore insaspettato: </translation> + <translation>errore inaspettato: </translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="1045"/> @@ -312,7 +312,7 @@ <message> <location filename="../src/wallet/api/wallet.cpp" line="1419"/> <source>Rescan spent can only be used with a trusted daemon</source> - <translation>"riscannerizza spesi" può essere utilizzato solo da un daemon fidato</translation> + <translation>"Riscannerizza spesi" può essere utilizzato solo da un daemon fidato</translation> </message> </context> <context> @@ -320,38 +320,38 @@ <message> <location filename="../src/wallet/api/wallet_manager.cpp" line="192"/> <source>failed to parse txid</source> - <translation>analisi(parse) txid fallita</translation> + <translation>analisi txid fallita</translation> </message> <message> <location filename="../src/wallet/api/wallet_manager.cpp" line="199"/> <location filename="../src/wallet/api/wallet_manager.cpp" line="206"/> <source>failed to parse tx key</source> - <translation>analisi(parse) chiave tx fallita</translation> + <translation>parsing chiave tx fallito</translation> </message> <message> <location filename="../src/wallet/api/wallet_manager.cpp" line="217"/> <source>failed to parse address</source> - <translation>analisi(parse) indirizzo fallita</translation> + <translation>parsing indirizzo fallito</translation> </message> <message> <location filename="../src/wallet/api/wallet_manager.cpp" line="227"/> <source>failed to get transaction from daemon</source> - <translation>impossibile recuperare transazione da daemon</translation> + <translation>impossibile recuperare la transazione dal daemon</translation> </message> <message> <location filename="../src/wallet/api/wallet_manager.cpp" line="238"/> <source>failed to parse transaction from daemon</source> - <translation>impossibile analizzare(parse) transazione dal daemon</translation> + <translation>impossibile fare il parsing della transazione dal daemon</translation> </message> <message> <location filename="../src/wallet/api/wallet_manager.cpp" line="245"/> <source>failed to validate transaction from daemon</source> - <translation>convalida transazione da daemon fallita</translation> + <translation>convalida transazione dal daemon fallita</translation> </message> <message> <location filename="../src/wallet/api/wallet_manager.cpp" line="250"/> <source>failed to get the right transaction from daemon</source> - <translation>Impossibile recuperare la giusta transazione dal daemon</translation> + <translation>impossibile recuperare la giusta transazione dal daemon</translation> </message> <message> <location filename="../src/wallet/api/wallet_manager.cpp" line="257"/> @@ -376,7 +376,7 @@ <message> <location filename="../src/wallet/api/wallet_manager.cpp" line="323"/> <source>received nothing in txid</source> - <translation>ricevuto nulla in txid</translation> + <translation>nulla ricevuto in txid</translation> </message> </context> <context> @@ -384,17 +384,17 @@ <message> <location filename="../src/wallet/api/wallet.cpp" line="212"/> <source>Failed to parse address</source> - <translation>Analisi(parse) indirizzo fallita</translation> + <translation>Parsing indirizzo fallito</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="219"/> <source>Failed to parse key</source> - <translation>Analisi(parse) key fallita</translation> + <translation>Parsing chiave fallito</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="227"/> <source>failed to verify key</source> - <translation>verifica key fallita</translation> + <translation>verifica chiave fallita</translation> </message> <message> <location filename="../src/wallet/api/wallet.cpp" line="237"/> @@ -430,7 +430,7 @@ <message> <location filename="../src/rpc/rpc_args.cpp" line="66"/> <source>Invalid IP address given for --</source> - <translation>Invalido indirizzo IP dato per --</translation> + <translation>Indirizzo IP non valido dato per --</translation> </message> <message> <location filename="../src/rpc/rpc_args.cpp" line="74"/> @@ -445,7 +445,7 @@ <message> <location filename="../src/rpc/rpc_args.cpp" line="89"/> <source> cannot be empty</source> - <translation> non puoò essere vuoto</translation> + <translation> non può essere vuoto</translation> </message> </context> <context> @@ -458,7 +458,7 @@ <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1557"/> <source>failed to read wallet password</source> - <translation>impossibile leggere password portafoglio</translation> + <translation>impossibile leggere la password del portafoglio</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1325"/> @@ -468,12 +468,12 @@ <message> <location filename="../src/simplewallet/simplewallet.cpp" line="697"/> <source>start_mining [<number_of_threads>] - Start mining in daemon</source> - <translation>inizia a minare [<number_of_threads>] - Inizia a minare nel daemon</translation> + <translation>start_mining [<number_of_threads>] - Avvia mining nel daemon</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="698"/> <source>Stop mining in daemon</source> - <translation>interrompi mining nel daemon</translation> + <translation>Interrompi mining nel daemon</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="699"/> @@ -493,7 +493,7 @@ <message> <location filename="../src/simplewallet/simplewallet.cpp" line="715"/> <source>Show current wallet public address</source> - <translation>Mostra indirizzo pubblico del corrente portafoglio</translation> + <translation>Mostra indirizzo pubblico del portafoglio corrente</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="744"/> @@ -503,7 +503,7 @@ <message> <location filename="../src/simplewallet/simplewallet.cpp" line="788"/> <source>set seed: needs an argument. available options: language</source> - <translation>imposta seme: richiede una definizione. opzioni disponibili: lingua</translation> + <translation>imposta seed: richiede una definizione. opzioni disponibili: lingua</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="811"/> @@ -538,12 +538,12 @@ <message> <location filename="../src/simplewallet/simplewallet.cpp" line="728"/> <source>Check tx proof for payment going to <address> in <txid></source> - <translation type="unfinished"></translation> + <translation>Verifica prova tx per pagamento inviato a <indirizzo> in <txid></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="743"/> <source>Generate a new random full size payment id - these will be unencrypted on the blockchain, see integrated_address for encrypted short payment ids</source> - <translation type="unfinished"></translation> + <translation>Genera un nuovo id pagamento casuale di dimensione completa - queste non saranno criptate nel blockchain, considera integrated_address per payment ids corti crittati</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="774"/> @@ -564,7 +564,7 @@ <message> <location filename="../src/simplewallet/simplewallet.cpp" line="800"/> <source>integer >= 2</source> - <translation type="unfinished"></translation> + <translation>integrale >= 2</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="803"/> @@ -585,12 +585,12 @@ <message> <location filename="../src/simplewallet/simplewallet.cpp" line="973"/> <source>specify a recovery parameter with the --electrum-seed="words list here"</source> - <translation>Specificare un parametro di ripristino con --electrum-seed="lista parole qui"</translation> + <translation>specificare un parametro di ripristino con --electrum-seed="lista parole qui"</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1261"/> <source>wallet failed to connect to daemon: </source> - <translation>impossibile connettere portafoglio a daemon: </translation> + <translation>impossibile connettere il portafoglio al daemon: </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1269"/> @@ -600,7 +600,7 @@ <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1288"/> <source>List of available languages for your wallet's seed:</source> - <translation>Lista delle lingue disponibili per il seme del tuo portafoglio:</translation> + <translation>Lista delle lingue disponibili per il seed del tuo portafoglio:</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1297"/> @@ -611,7 +611,7 @@ <location filename="../src/simplewallet/simplewallet.cpp" line="1354"/> <source>You had been using a deprecated version of the wallet. Please use the new seed that we provide. </source> - <translation>Hai usato una versione obsoleta del portafoglio. Per favore usa il nuovo seme che ti abbiamo fornito.</translation> + <translation>Hai usato una versione obsoleta del portafoglio. Per favore usa il nuovo seed che ti abbiamo fornito.</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1368"/> @@ -666,12 +666,12 @@ <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1613"/> <source>Mining started in daemon</source> - <translation>Mining partito nel daemon</translation> + <translation>Mining avviato nel daemon</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1615"/> <source>mining has NOT been started: </source> - <translation>il mining NON è partito: </translation> + <translation>il mining NON è stato avviato: </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1634"/> @@ -681,7 +681,7 @@ <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1636"/> <source>mining has NOT been stopped: </source> - <translation>Il mining NON è stato interrotto: </translation> + <translation>il mining NON è stato interrotto: </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1655"/> @@ -710,7 +710,7 @@ <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1689"/> <source>spent </source> - <translation>speso/i</translation> + <translation>speso/i </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1701"/> @@ -720,7 +720,7 @@ <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1718"/> <source>Starting refresh...</source> - <translation>Iniziando refresh...</translation> + <translation>Sto iniziando il refresh...</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1731"/> @@ -736,7 +736,7 @@ <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2201"/> <source>bad locked_blocks parameter:</source> - <translation>parametro locked_blocks difettoso:</translation> + <translation>parametro locked_blocks non corretto:</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2228"/> @@ -762,17 +762,17 @@ <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2323"/> <source>Sending %s. </source> - <translation>Inviando %s. </translation> + <translation>Sto inviando %s. </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2326"/> <source>Your transaction needs to be split into %llu transactions. This will result in a transaction fee being applied to each transaction, for a total fee of %s</source> - <translation>La tua transazione deve essere divisa in %llu transazioni. Una tassa verrà applicata per ogni transazione, per un totale di %s tasse</translation> + <translation>La tua transazione deve essere divisa in %llu transazioni. Una commissione verrà applicata per ogni transazione, per un totale di %s commissioni</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2332"/> <source>The transaction fee is %s</source> - <translation>la tassa per la transazione è %s</translation> + <translation>La commissione per la transazione è %s</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2335"/> @@ -793,7 +793,8 @@ <location filename="../src/simplewallet/simplewallet.cpp" line="2341"/> <source>. This transaction will unlock on block %llu, in approximately %s days (assuming 2 minutes per block)</source> - <translation>Questa transazione verrà sbloccata al blocco %llu, in approssimativamente %s giorni (supponendo 2 minuti per blocco)</translation> + <translation>. +Questa transazione verrà sbloccata al blocco %llu, in approssimativamente %s giorni (supponendo 2 minuti per blocco)</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2367"/> @@ -823,7 +824,7 @@ This transaction will unlock on block %llu, in approximately %s days (assuming 2 <location filename="../src/simplewallet/simplewallet.cpp" line="2853"/> <location filename="../src/simplewallet/simplewallet.cpp" line="3166"/> <source>Failed to find a way to create transactions. This is usually due to dust which is so small it cannot pay for itself in fees, or trying to send more money than the unlocked balance, or not leaving enough for fees</source> - <translation>Impossibile creare transazioni. Questo succede di solito perchè l'ammontare di polvere è così piccolo da non poter pagare le proprie tasse, oppure stai provando a mandare più soldi di quelli che possiedi nel bilancio sbloccato, o non hai aggiunto abbastanza tasse</translation> + <translation>Impossibile creare transazioni. Questo succede di solito perchè l'ammontare di polvere è così piccolo da non poter pagare le proprie commissioni, oppure stai provando a mandare più fondi di quelli che possiedi nel bilancio sbloccato, o non hai aggiunto abbastanza commissioni</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2435"/> @@ -837,7 +838,7 @@ This transaction will unlock on block %llu, in approximately %s days (assuming 2 <location filename="../src/simplewallet/simplewallet.cpp" line="2624"/> <location filename="../src/simplewallet/simplewallet.cpp" line="2885"/> <source>failed to find a suitable way to split transactions</source> - <translation>Impossibile trovare un modo adatto per dividere le transazioni</translation> + <translation>impossibile trovare un modo adatto per dividere le transazioni</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2503"/> @@ -862,7 +863,7 @@ This transaction will unlock on block %llu, in approximately %s days (assuming 2 <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3035"/> <source>sending %s to %s</source> - <translation>mandando %s a %s</translation> + <translation>sto mandando %s a %s</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3041"/> @@ -882,7 +883,7 @@ This transaction will unlock on block %llu, in approximately %s days (assuming 2 <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3120"/> <source>Failed to load transaction from file</source> - <translation>caricamento transazione da file fallito</translation> + <translation>Caricamento transazione da file fallito</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3137"/> @@ -902,7 +903,7 @@ This transaction will unlock on block %llu, in approximately %s days (assuming 2 <message> <location filename="../src/simplewallet/simplewallet.cpp" line="312"/> <source>wallet is watch-only and has no spend key</source> - <translation>il portafoglio è solo-vista e non ha una chiave spendibile</translation> + <translation>il portafoglio è solo-vista e non ha una chiave di spesa</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="390"/> @@ -998,7 +999,7 @@ This transaction will unlock on block %llu, in approximately %s days (assuming 2 <location filename="../src/simplewallet/simplewallet.cpp" line="1157"/> <location filename="../src/simplewallet/simplewallet.cpp" line="1184"/> <source>bad m_restore_height parameter: </source> - <translation>parametro m_restore_height scorretto: </translation> + <translation>parametro m_restore_height non corretto: </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1162"/> @@ -1008,18 +1009,18 @@ This transaction will unlock on block %llu, in approximately %s days (assuming 2 <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1175"/> <source>Restore height is: </source> - <translation>ripristina altezza è: </translation> + <translation>Ripristina altezza è: </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1176"/> <location filename="../src/simplewallet/simplewallet.cpp" line="2348"/> <source>Is this okay? (Y/Yes/N/No): </source> - <translation>va bene? (S/Sì/N/No): </translation> + <translation>Va bene? (S/Sì/N/No): </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1212"/> <source>Daemon is local, assuming trusted</source> - <translation>Il daemon è locale, assunto per fidato</translation> + <translation>Il daemon è locale, viene considerato fidato</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1553"/> @@ -1100,12 +1101,12 @@ This transaction will unlock on block %llu, in approximately %s days (assuming 2 <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1868"/> <source>No incoming transfers</source> - <translation>nessun trasferimento in entrata</translation> + <translation>Nessun trasferimento in entrata</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1872"/> <source>No incoming available transfers</source> - <translation>nessun trasferimento in entrata disponibile</translation> + <translation>Nessun trasferimento in entrata disponibile</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1876"/> @@ -1130,7 +1131,7 @@ This transaction will unlock on block %llu, in approximately %s days (assuming 2 <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1896"/> <source>height</source> - <translation>blocco</translation> + <translation>altezza</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1896"/> @@ -1140,14 +1141,14 @@ This transaction will unlock on block %llu, in approximately %s days (assuming 2 <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1908"/> <source>No payments with id </source> - <translation>nessun pagamento con id </translation> + <translation>Nessun pagamento con id </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1960"/> <location filename="../src/simplewallet/simplewallet.cpp" line="2026"/> <location filename="../src/simplewallet/simplewallet.cpp" line="2280"/> <source>failed to get blockchain height: </source> - <translation>impossibile recuperare dalla </translation> + <translation>impossibile recuperare altezza blockchain: </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2016"/> @@ -1158,7 +1159,8 @@ This transaction will unlock on block %llu, in approximately %s days (assuming 2 <location filename="../src/simplewallet/simplewallet.cpp" line="2034"/> <source> Transaction %llu/%llu: txid=%s</source> - <translation>Transazione %llu/%llu: txid=%s</translation> + <translation> +Transazione %llu/%llu: txid=%s</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2044"/> @@ -1174,13 +1176,14 @@ Input %llu/%llu: amount=%s</source> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2068"/> <source>output key's originating block height shouldn't be higher than the blockchain height</source> - <translation type="unfinished"></translation> + <translation>l'altezza del blocco di origine della chiave di output non dovrebbe essere più alta dell'altezza della blockchain</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2072"/> <source> Originating block heights: </source> - <translation>Originando blocchi: </translation> + <translation> +Originando blocchi: </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2087"/> @@ -1201,24 +1204,25 @@ Originating block heights: </source> <location filename="../src/simplewallet/simplewallet.cpp" line="2104"/> <source> Warning: Some input keys being spent are from </source> - <translation>Avvertimento: alcune chiavi di input spese vengono da </translation> + <translation> +Avviso: alcune chiavi di input spese vengono da </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2106"/> <source>, which can break the anonymity of ring signature. Make sure this is intentional!</source> - <translation>, che potrebbe rempere l'anonimità delle firme ad anello. Assicurati di farlo intenzionalmente!</translation> + <translation>, che potrebbe compromettere l'anonimità della ring signature. Assicurati di farlo intenzionalmente!</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2152"/> <location filename="../src/simplewallet/simplewallet.cpp" line="2937"/> <source>wrong number of arguments</source> - <translation>errato numero di argomenti</translation> + <translation>numero di argomenti errato</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2257"/> <location filename="../src/simplewallet/simplewallet.cpp" line="2744"/> <source>No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): </source> - <translation>Nessun id pagamento incluso in questa transazione. Questo è corretto? (S/Sì/N/No): </translation> + <translation>Nessun id pagamento è incluso in questa transazione. Questo è corretto? (S/Sì/N/No): </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2298"/> @@ -1238,12 +1242,12 @@ Warning: Some input keys being spent are from </source> <location filename="../src/simplewallet/simplewallet.cpp" line="2518"/> <location filename="../src/simplewallet/simplewallet.cpp" line="2779"/> <source>Sweeping %s in %llu transactions for a total fee of %s. Is this okay? (Y/Yes/N/No): </source> - <translation>Eseguendo lo sweep di %s nelle transazioni %llu per un totale di tasse di %s. Va bene? (S/Sì/N/No): </translation> + <translation>Sto eseguendo lo sweep di %s nelle transazioni %llu per un totale commissioni di %s. Va bene? (S/Sì/N/No): </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2524"/> <source>Sweeping %s for a total fee of %s. Is this okay? (Y/Yes/N/No): </source> - <translation>Eseguendo lo sweep di %s per un totale di tasse di %s. Va bene? (S/Sì/N/No): </translation> + <translation>Sto eseguendo lo sweep di %s per un totale commissioni di %s. Va bene? (S/Sì/N/No): </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2969"/> @@ -1253,12 +1257,12 @@ Warning: Some input keys being spent are from </source> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3053"/> <source>Loaded %lu transactions, for %s, fee %s, %s, %s, with min mixin %lu. %sIs this okay? (Y/Yes/N/No): </source> - <translation>Caricate %lu transazioni, per %s, tasse %s, %s, %s, con mixaggio %lu. %sQuesto è corretto? (S/Sì/N/No): </translation> + <translation>Caricate %lu transazioni, per %s, commissioni %s, %s, %s, con mixaggio %lu. %sQuesto è corretto? (S/Sì/N/No): </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3077"/> <source>This is a watch only wallet</source> - <translation>questo è un portafoglio solo-vista</translation> + <translation>Questo è un portafoglio solo-vista</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4443"/> @@ -1278,19 +1282,19 @@ Warning: Some input keys being spent are from </source> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="266"/> <source>failed to parse refresh type</source> - <translation>impossibile analizzare (parse) tipo di refresh</translation> + <translation>impossibile fare il parsing del tipo di refresh</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="330"/> <location filename="../src/simplewallet/simplewallet.cpp" line="362"/> <source>wallet is watch-only and has no seed</source> - <translation>il portafoglio è solo-vista e non possiede un seme</translation> + <translation>il portafoglio è solo-vista e non possiede un seed</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="353"/> <location filename="../src/simplewallet/simplewallet.cpp" line="367"/> <source>wallet is non-deterministic and has no seed</source> - <translation>il portafoglio è non-deterministico e non possiede un seme</translation> + <translation>il portafoglio è non-deterministico e non possiede un seed</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="450"/> @@ -1308,7 +1312,7 @@ Warning: Some input keys being spent are from </source> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="501"/> <source>could not change default mixin</source> - <translation>impossibile cambiare mixxaggio standard</translation> + <translation>impossibile cambiare mixin standard</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="545"/> @@ -1338,7 +1342,7 @@ Warning: Some input keys being spent are from </source> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="707"/> <source>locked_transfer [<mixin_count>] <addr> <amount> <lockblocks>(Number of blocks to lock the transaction for, max 1000000) [<payment_id>]</source> - <translation type="unfinished"></translation> + <translation>locked_transfer [<mixin_count>] <addr> <amount> <lockblocks>(Numero di blocchi durante i quali bloccare la transazione, max 1000000) [<payment_id>]</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="708"/> @@ -1353,12 +1357,12 @@ Warning: Some input keys being spent are from </source> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="713"/> <source>Submit a signed transaction from a file</source> - <translation>Invia una transazione dirmata da file</translation> + <translation>Invia una transazione firmata da file</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="716"/> <source>integrated_address [PID] - Encode a payment ID into an integrated address for the current wallet public address (no argument uses a random payment ID), or decode an integrated address to standard address and payment ID</source> - <translation type="unfinished"></translation> + <translation>integrated_address [PID] - Codifica un ID pagamento in un indirizzo integrato per l'indirizzo pubblico del portafoglio corrente (nessun parametro usa un payment ID casuale), oppure decodifica un indirizzo integrato in indirizzo standard e payment ID</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="718"/> @@ -1378,22 +1382,22 @@ Warning: Some input keys being spent are from </source> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="721"/> <source>Display private spend key</source> - <translation>Visualizza chiave privata spendibile</translation> + <translation>Visualizza chiave di spesa privata</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="722"/> <source>Display Electrum-style mnemonic seed</source> - <translation>Visualizza il seme mnemonico in stile Electrum</translation> + <translation>Visualizza il seed mnemonico in stile Electrum</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="723"/> <source>Available options: seed language - set wallet seed language; always-confirm-transfers <1|0> - whether to confirm unsplit txes; print-ring-members <1|0> - whether to print detailed information about ring members during confirmation; store-tx-info <1|0> - whether to store outgoing tx info (destination address, payment ID, tx secret key) for future reference; default-mixin <n> - set default mixin (default is 4); auto-refresh <1|0> - whether to automatically sync new blocks from the daemon; refresh-type <full|optimize-coinbase|no-coinbase|default> - set wallet refresh behaviour; priority [0|1|2|3|4] - default/unimportant/normal/elevated/priority fee; confirm-missing-payment-id <1|0>; ask-password <1|0>; unit <monero|millinero|micronero|nanonero|piconero> - set default monero (sub-)unit; min-outputs-count [n] - try to keep at least that many outputs of value at least min-outputs-value; min-outputs-value [n] - try to keep at least min-outputs-count outputs of at least that value; merge-destinations <1|0> - whether to merge multiple payments to the same destination address</source> - <translation type="unfinished"></translation> + <translation>Opzioni disponibili: seed language - seleziona lingua del seed per il portafoglio; always-confirm-transfers <1|0> - se confermare unsplit txes; print-ring-members <1|0> - se mostrare informazioni dettagliate sui ring members durante le conferme; store-tx-info <1|0> - se salvare le informazioni tx in uscita (indirizzo di destinazione, payment ID, chiave tx segreta) per riferimento futuro; default-mixin <n> - imposta default mixin (default è 4); auto-refresh <1|0> - se sincronizzare automaticamente i nuovi blocchi dal daemon; refresh-type <full|optimize-coinbase|no-coinbase|default> - imposta modalità wallet refresh; priority [0|1|2|3|4] - default/unimportant/normal/elevated/priority fee; confirm-missing-payment-id <1|0>; ask-password <1|0>; unit <monero|millinero|micronero|nanonero|piconero> - imposta default monero (sub-)unit; min-outputs-count [n] - cerca di mantenere come minimo tanti outputs quanti il valore di min-outputs-value; min-outputs-value [n] - cerca di mantenere i min-outputs-count outputs come minimo a questo valore; merge-destinations <1|0> - se fondere pagamenti multipli allo stessp indirizzo di destinazione</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="724"/> <source>Rescan blockchain for spent outputs</source> - <translation>Riscannerizza blockchain in cerca di outputs non spesi</translation> + <translation>Riscannerizza blockchain in cerca di outputs spesi</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="725"/> @@ -1408,12 +1412,12 @@ Warning: Some input keys being spent are from </source> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="730"/> <source>unspent_outputs [<min_amount> <max_amount>] - Show unspent outputs within an optional amount range</source> - <translation type="unfinished"></translation> + <translation>unspent_outputs [<min_amount> <max_amount>] - Mostra gli outputs non spesi entro un intervallo di valori opzionale</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="731"/> <source>Rescan blockchain from scratch</source> - <translation>Riscannerizza blockchain dal principio</translation> + <translation>Avvia scansione blockchain dal principio</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="732"/> @@ -1423,7 +1427,7 @@ Warning: Some input keys being spent are from </source> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="733"/> <source>Get a string note for a txid</source> - <translation type="unfinished"></translation> + <translation>Ricevi una stringa di annotazione per un txid</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="734"/> @@ -1463,12 +1467,12 @@ Warning: Some input keys being spent are from </source> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="802"/> <source>full (slowest, no assumptions); optimize-coinbase (fast, assumes the whole coinbase is paid to a single address); no-coinbase (fastest, assumes we receive no coinbase transaction), default (same as optimize-coinbase)</source> - <translation type="unfinished"></translation> + <translation>completo (più lento, nessuna ipotesi); optimize-coinbase (veloce, ipotizza che l'intero coinbase viene pagato ad un indirizzo singolo); no-coinbase (il più veloce, ipotizza di non ricevere una transazione coinbase), default (come optimize-coinbase)</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="806"/> <source>monero, millinero, micronero, nanonero, piconero</source> - <translation type="unfinished"></translation> + <translation>monero, millinero, micronero, nanonero, piconero</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="851"/> @@ -1478,12 +1482,12 @@ Warning: Some input keys being spent are from </source> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="868"/> <source>Wallet and key files found, loading...</source> - <translation>Portafoglio e chiavi trovatr, sto caricando...</translation> + <translation>Portafoglio e chiavi trovate, sto caricando...</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="874"/> <source>Key file found but not wallet file. Regenerating...</source> - <translation>Ho trovato la chiave ma non il portafoglio. Rigenerando...</translation> + <translation>Ho trovato la chiave ma non il portafoglio. Sto rigenerando...</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="880"/> @@ -1535,25 +1539,25 @@ Warning: Some input keys being spent are from </source> <location filename="../src/simplewallet/simplewallet.cpp" line="4048"/> <location filename="../src/simplewallet/simplewallet.cpp" line="4239"/> <source>failed to parse address</source> - <translation>impossibile analizzare(parse) indirizzo</translation> + <translation>impossibile fare il parsing dell'indirizzo</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1017"/> <location filename="../src/simplewallet/simplewallet.cpp" line="1085"/> <source>failed to parse view key secret key</source> - <translation>impossibile analizzare(parse) chiave per visualizzazione chiave segreta</translation> + <translation>impossibile fare il parsing chiave di visualizzazione chiave segreta</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1027"/> <location filename="../src/simplewallet/simplewallet.cpp" line="1103"/> <source>failed to verify view key secret key</source> - <translation>impossibile verificare chiave segreta vista</translation> + <translation>impossibile verificare chiave di visualizzazione chiave segreta</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1031"/> <location filename="../src/simplewallet/simplewallet.cpp" line="1107"/> <source>view key does not match standard address</source> - <translation>la chiave per visualizzazione non corrisponde all'indirizzo standard</translation> + <translation>la chiave di visualizzazione non corrisponde all'indirizzo standard</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1036"/> @@ -1565,22 +1569,22 @@ Warning: Some input keys being spent are from </source> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1069"/> <source>failed to parse spend key secret key</source> - <translation>impossibile analizzare (parse) chiave spendibile chiave segreta</translation> + <translation>impossibile fare il parsing chiave di spesa chiave segreta</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1095"/> <source>failed to verify spend key secret key</source> - <translation>impossibile verificare chiave spendibile chiave segreta</translation> + <translation>impossibile verificare chiave di spesa chiave segreta</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1099"/> <source>spend key does not match standard address</source> - <translation>la chiave spendibile non corrisponde all'indirizzo standard</translation> + <translation>la chiave di spesa non corrisponde all'indirizzo standard</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1123"/> <source>specify a wallet path with --generate-new-wallet (not --wallet-file)</source> - <translation>specifica un nuovo percorso per il portafoglio con --generate-new-wallet (non --wallet-file)</translation> + <translation>specifica un percorso per il portafoglio con --generate-new-wallet (non --wallet-file)</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1199"/> @@ -1611,7 +1615,7 @@ Warning: Some input keys being spent are from </source> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1370"/> <source>View key: </source> - <translation>Chiave per visualizzazione: </translation> + <translation>Chiave di visualizzazione: </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1385"/> @@ -1648,7 +1652,7 @@ di nuovo il tuo portafoglio (le chiavi del tuo portafoglio NON sono a rischio in <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1657"/> <source>blockchain can't be saved: </source> - <translation>impossibile salvare blockchain: </translation> + <translation>impossibile salvare la blockchain: </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1736"/> @@ -1671,7 +1675,7 @@ di nuovo il tuo portafoglio (le chiavi del tuo portafoglio NON sono a rischio in <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1750"/> <source>refresh error: </source> - <translation>refresh errore: </translation> + <translation>errore refresh: </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="1794"/> @@ -1737,17 +1741,17 @@ di nuovo il tuo portafoglio (le chiavi del tuo portafoglio NON sono a rischio in <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2105"/> <source>the same transaction</source> - <translation type="unfinished"></translation> + <translation>la stessa transazione</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2105"/> <source>blocks that are temporally very close</source> - <translation type="unfinished"></translation> + <translation>i blocchi che sono temporalmente molto vicini</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2206"/> <source>Locked blocks too high, max 1000000 (˜4 yrs)</source> - <translation type="unfinished"></translation> + <translation>I blocchi bloccati sono troppo alti, max 1000000 (˜4 anni)</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2921"/> @@ -1772,7 +1776,7 @@ di nuovo il tuo portafoglio (le chiavi del tuo portafoglio NON sono a rischio in <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3289"/> <source>failed to parse tx_key</source> - <translation>impossibile analizzare (parse) tx_key</translation> + <translation>impossibile fare il parsing del tx_key</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3298"/> @@ -1797,7 +1801,7 @@ di nuovo il tuo portafoglio (le chiavi del tuo portafoglio NON sono a rischio in <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3539"/> <source>Signature header check error</source> - <translation>errore controllo firma intestazione</translation> + <translation>Errore controllo firma intestazione</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3550"/> @@ -1844,7 +1848,7 @@ di nuovo il tuo portafoglio (le chiavi del tuo portafoglio NON sono a rischio in <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4027"/> <source>failed to parse payment ID or address</source> - <translation>impossibile analizzare (parse) ID pagamento o indirizzo</translation> + <translation>impossibile fare il parsing di ID pagamento o indirizzo</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4038"/> @@ -1854,12 +1858,12 @@ di nuovo il tuo portafoglio (le chiavi del tuo portafoglio NON sono a rischio in <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4070"/> <source>failed to parse payment ID</source> - <translation>impossibile analizzare (parse) ID pagamento</translation> + <translation>impossibile fare il parsing di ID pagamento</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4088"/> <source>failed to parse index</source> - <translation>impossibile analizzare (parse) indice</translation> + <translation>impossibile fare il parsing dell'indice</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4096"/> @@ -1899,7 +1903,7 @@ di nuovo il tuo portafoglio (le chiavi del tuo portafoglio NON sono a rischio in <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4193"/> <source>usage: sign <filename></source> - <translation type="unfinished"></translation> + <translation>uso: sign <filename></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4198"/> @@ -1911,7 +1915,7 @@ di nuovo il tuo portafoglio (le chiavi del tuo portafoglio NON sono a rischio in <location filename="../src/simplewallet/simplewallet.cpp" line="4230"/> <location filename="../src/simplewallet/simplewallet.cpp" line="4374"/> <source>failed to read file </source> - <translation>impossibile leggere file </translation> + <translation>impossibile leggere il file </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4219"/> @@ -1921,7 +1925,7 @@ di nuovo il tuo portafoglio (le chiavi del tuo portafoglio NON sono a rischio in <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4246"/> <source>Bad signature from </source> - <translation>Firma invalida da </translation> + <translation>Firma non valida da </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4250"/> @@ -1957,7 +1961,7 @@ di nuovo il tuo portafoglio (le chiavi del tuo portafoglio NON sono a rischio in <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4323"/> <source>usage: export_outputs <filename></source> - <translation>usage: export_outputs <filename></translation> + <translation>uso: export_outputs <filename></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="4357"/> @@ -1973,7 +1977,7 @@ di nuovo il tuo portafoglio (le chiavi del tuo portafoglio NON sono a rischio in <location filename="../src/simplewallet/simplewallet.cpp" line="2246"/> <location filename="../src/simplewallet/simplewallet.cpp" line="3818"/> <source>amount is wrong: </source> - <translation>l'ammontare è scorretto: </translation> + <translation>l'ammontare non è corretto: </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2247"/> @@ -2042,7 +2046,7 @@ di nuovo il tuo portafoglio (le chiavi del tuo portafoglio NON sono a rischio in <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3195"/> <source>Failed to find a suitable way to split transactions</source> - <translation>Impossibile trovare un modo corretto per dividere transazioni</translation> + <translation>Impossibile trovare un modo corretto per dividere le transazioni</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2452"/> @@ -2055,19 +2059,19 @@ di nuovo il tuo portafoglio (le chiavi del tuo portafoglio NON sono a rischio in <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2516"/> <source>Sweeping </source> - <translation>Pulendo (sweeping) </translation> + <translation>Eseguendo lo sweeping </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2785"/> <source>Sweeping %s for a total fee of %s. Is this okay? (Y/Yes/N/No)</source> - <translation>Eseguendo lo sweeping di %s per un totale di tasse di %s. Va bene? (S/Sì/N/No)</translation> + <translation>Eseguendo lo sweeping di %s per un totale commissioni di %s. Va bene? (S/Sì/N/No)</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="2555"/> <location filename="../src/simplewallet/simplewallet.cpp" line="2816"/> <location filename="../src/simplewallet/simplewallet.cpp" line="3129"/> <source>Money successfully sent, transaction: </source> - <translation>Soldi inviati con successo, transazione: </translation> + <translation>Fondi inviati con successo, transazione: </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3047"/> @@ -2098,7 +2102,7 @@ di nuovo il tuo portafoglio (le chiavi del tuo portafoglio NON sono a rischio in <location filename="../src/simplewallet/simplewallet.cpp" line="4150"/> <location filename="../src/simplewallet/simplewallet.cpp" line="4450"/> <source>failed to parse txid</source> - <translation>analisi(parse) txid fallita</translation> + <translation>parsing txid fallito</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3245"/> @@ -2119,19 +2123,19 @@ di nuovo il tuo portafoglio (le chiavi del tuo portafoglio NON sono a rischio in <location filename="../src/simplewallet/simplewallet.cpp" line="3361"/> <location filename="../src/simplewallet/simplewallet.cpp" line="3368"/> <source>failed to parse tx key</source> - <translation>impossibile analizzare (parse) chiave tx</translation> + <translation>impossibile fare il parsing della chiave tx</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3400"/> <location filename="../src/simplewallet/simplewallet.cpp" line="3573"/> <source>failed to get transaction from daemon</source> - <translation>impossibil recuperare transazione dal daemon</translation> + <translation>impossibile recuperare transazione dal daemon</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3411"/> <location filename="../src/simplewallet/simplewallet.cpp" line="3584"/> <source>failed to parse transaction from daemon</source> - <translation>impossibile analizzare (parse) la transazione dal daemon</translation> + <translation>impossibile fare il parsing della transazione dal daemon</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3418"/> @@ -2168,12 +2172,12 @@ di nuovo il tuo portafoglio (le chiavi del tuo portafoglio NON sono a rischio in <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3481"/> <source>received nothing in txid</source> - <translation>ricevuto niente in txid</translation> + <translation>nulla ricevuto in txid</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3485"/> <source>WARNING: this transaction is not yet included in the blockchain!</source> - <translation>AVVERTIMENTO: questa transazione non è ancora inclusa nella blockchain!</translation> + <translation>AVVISO: questa transazione non è ancora inclusa nella blockchain!</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3494"/> @@ -2183,7 +2187,7 @@ di nuovo il tuo portafoglio (le chiavi del tuo portafoglio NON sono a rischio in <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3498"/> <source>WARNING: failed to determine number of confirmations!</source> - <translation>AVVERTIMENTO: impossibile determinare numero di conferme!</translation> + <translation>AVVISO: impossibile determinare il numero di conferme!</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3661"/> @@ -2193,12 +2197,12 @@ di nuovo il tuo portafoglio (le chiavi del tuo portafoglio NON sono a rischio in <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3700"/> <source>bad min_height parameter:</source> - <translation>parametro min_height scorretto:</translation> + <translation>parametro min_height non corretto:</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3712"/> <source>bad max_height parameter:</source> - <translation>parametro max_height scorretto:</translation> + <translation>parametro max_height non corretto:</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3760"/> @@ -2235,7 +2239,8 @@ di nuovo il tuo portafoglio (le chiavi del tuo portafoglio NON sono a rischio in <location filename="../src/simplewallet/simplewallet.cpp" line="3856"/> <source> Amount: </source> - <translation>Ammontare: </translation> + <translation> +Ammontare: </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3856"/> @@ -2251,43 +2256,49 @@ Amount: </source> <location filename="../src/simplewallet/simplewallet.cpp" line="3866"/> <source> Min block height: </source> - <translation>Altezza minima blocco: </translation> + <translation> +Altezza minima blocco: </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3867"/> <source> Max block height: </source> - <translation>Altezza massima blocco: </translation> + <translation> +Altezza massima blocco: </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3868"/> <source> Min amount found: </source> - <translation>Ammontare minimo trovato: </translation> + <translation> +Ammontare minimo trovato: </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3869"/> <source> Max amount found: </source> - <translation>Ammontare massimo trovato: </translation> + <translation> +Ammontare massimo trovato: </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3870"/> <source> Total count: </source> - <translation>Conto totale: </translation> + <translation> +Conto totale: </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3910"/> <source> Bin size: </source> - <translation>Dimensione Bin</translation> + <translation> +Dimensione Bin: </translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3911"/> <source> Outputs per *: </source> - <translation></translation> + <translation type="unfinished"></translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="3913"/> @@ -2356,7 +2367,7 @@ Outputs per *: </source> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="117"/> <source>Generate incoming-only wallet from view key</source> - <translation>Genera un portafoglio solo-ricezione da chiave per visualizzazione</translation> + <translation>Genera un portafoglio solo-ricezione da chiave di visualizzazione</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="118"/> @@ -2366,17 +2377,17 @@ Outputs per *: </source> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="120"/> <source>Specify Electrum seed for wallet recovery/creation</source> - <translation>Specifica il seme stile Electrum per recuperare/creare il portafoglio</translation> + <translation>Specifica il seed stile Electrum per recuperare/creare il portafoglio</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="121"/> <source>Recover wallet using Electrum-style mnemonic seed</source> - <translation>Recupera portafoglio usando il seme mnemonico stile-Electrum</translation> + <translation>Recupera portafoglio usando il seed mnemonico stile-Electrum</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="122"/> <source>Create non-deterministic view and spend keys</source> - <translation>Crea chiavi per visualizzione e chiavi spendibili non-deterministiche</translation> + <translation>Crea chiavi di visualizzione e chiavi di spesa non-deterministiche</translation> </message> <message> <location filename="../src/simplewallet/simplewallet.cpp" line="123"/> @@ -2424,7 +2435,7 @@ Outputs per *: </source> <message> <location filename="../src/common/dns_utils.cpp" line="434"/> <source>WARNING: DNSSEC validation was unsuccessful, this address may not be correct!</source> - <translation>AVVERTIMENTO: convalida DNSSEC fallita, questo indirizzo potrebbe non essere corretto!</translation> + <translation>AVVISO: convalida DNSSEC fallita, questo indirizzo potrebbe non essere corretto!</translation> </message> <message> <location filename="../src/common/dns_utils.cpp" line="437"/> @@ -2434,7 +2445,7 @@ Outputs per *: </source> <message> <location filename="../src/common/dns_utils.cpp" line="439"/> <source> Monero Address = </source> - <translation>Indirizzo Monero = </translation> + <translation> Indirizzo Monero = </translation> </message> <message> <location filename="../src/common/dns_utils.cpp" line="441"/> @@ -2444,7 +2455,7 @@ Outputs per *: </source> <message> <location filename="../src/common/dns_utils.cpp" line="451"/> <source>you have cancelled the transfer request</source> - <translation>hai cancelliato la richiesta di transferimento</translation> + <translation>hai cancellato la richiesta di transferimento</translation> </message> </context> <context> @@ -2477,12 +2488,12 @@ Outputs per *: </source> <message> <location filename="../src/wallet/wallet2.cpp" line="112"/> <source>For testnet. Daemon must also be launched with --testnet flag</source> - <translation>Per testnet. Il Daemon può anche essere lanciato con la flag --testnet</translation> + <translation>Per testnet. Il daemon può anche essere lanciato con la flag --testnet</translation> </message> <message> <location filename="../src/wallet/wallet2.cpp" line="113"/> <source>Restricts to view-only commands</source> - <translation>Restringi i comandi a solo-vista</translation> + <translation>Restringi a comandi di tipo solo-vista</translation> </message> <message> <location filename="../src/wallet/wallet2.cpp" line="152"/> @@ -2517,7 +2528,7 @@ Outputs per *: </source> <message> <location filename="../src/wallet/wallet2.cpp" line="108"/> <source>Wallet password (escape/quote as needed)</source> - <translation type="unfinished"></translation> + <translation>Wallet password (escape/quote se necessario)</translation> </message> <message> <location filename="../src/wallet/wallet2.cpp" line="111"/> @@ -2527,46 +2538,46 @@ Outputs per *: </source> <message> <location filename="../src/wallet/wallet2.cpp" line="233"/> <source>Failed to parse JSON</source> - <translation>Impossibile analizzare (parse) JSON</translation> + <translation>Impossibile fare il parsing di JSON</translation> </message> <message> <location filename="../src/wallet/wallet2.cpp" line="240"/> <source>Version %u too new, we can only grok up to %u</source> - <translation type="unfinished"></translation> + <translation>La versione %u è troppo recente, possiamo comprendere solo fino alla versione %u</translation> </message> <message> <location filename="../src/wallet/wallet2.cpp" line="258"/> <source>failed to parse view key secret key</source> - <translation>impossibile analizzare (parse) chiave per visualizzazione chiave segreta</translation> + <translation>impossibile fare il parsing di chiave di visualizzazione chiave segreta</translation> </message> <message> <location filename="../src/wallet/wallet2.cpp" line="264"/> <location filename="../src/wallet/wallet2.cpp" line="331"/> <location filename="../src/wallet/wallet2.cpp" line="373"/> <source>failed to verify view key secret key</source> - <translation>impossibile verificare chiave per visualizzazione chiave segreta</translation> + <translation>impossibile verificare chiave di visualizzazione chiave segreta</translation> </message> <message> <location filename="../src/wallet/wallet2.cpp" line="276"/> <source>failed to parse spend key secret key</source> - <translation>impossibile analizzare (parse) chiave spendibile chiave segreta</translation> + <translation>impossibile fare il parsing chiave di spesa chiave segreta</translation> </message> <message> <location filename="../src/wallet/wallet2.cpp" line="282"/> <location filename="../src/wallet/wallet2.cpp" line="343"/> <location filename="../src/wallet/wallet2.cpp" line="394"/> <source>failed to verify spend key secret key</source> - <translation>impossibile verificare chiave spendibile chiave segreta</translation> + <translation>impossibile verificare chiave di spesa chiave segreta</translation> </message> <message> <location filename="../src/wallet/wallet2.cpp" line="295"/> <source>Electrum-style word list failed verification</source> - <translation>verifica lista di parole stile-Electrum fallita</translation> + <translation>Verifica lista di parole stile-Electrum fallita</translation> </message> <message> <location filename="../src/wallet/wallet2.cpp" line="306"/> <source>At least one of Electrum-style word list and private view key must be specified</source> - <translation></translation> + <translation>Almeno una parola della lista stile-Electrum e una chiave privata di visualizzazione devono essere specificate</translation> </message> <message> <location filename="../src/wallet/wallet2.cpp" line="311"/> @@ -2581,12 +2592,12 @@ Outputs per *: </source> <message> <location filename="../src/wallet/wallet2.cpp" line="335"/> <source>view key does not match standard address</source> - <translation>la chiave per visualizzazione non corrisponde all'indirizzo standard</translation> + <translation>la chiave di visualizzazione non corrisponde all'indirizzo standard</translation> </message> <message> <location filename="../src/wallet/wallet2.cpp" line="347"/> <source>spend key does not match standard address</source> - <translation>la chiave spendibile non corrisponde all'indirizzo standard</translation> + <translation>la chiave di spesa non corrisponde all'indirizzo standard</translation> </message> <message> <location filename="../src/wallet/wallet2.cpp" line="356"/> @@ -2609,7 +2620,7 @@ Outputs per *: </source> <message> <location filename="../src/wallet/wallet_rpc_server.cpp" line="151"/> <source>Daemon is local, assuming trusted</source> - <translation>Il daemon è locale, assunto per fidato</translation> + <translation>Il daemon è locale, viene considerato fidato</translation> </message> <message> <location filename="../src/wallet/wallet_rpc_server.cpp" line="171"/> @@ -2639,7 +2650,7 @@ Outputs per *: </source> <message> <location filename="../src/wallet/wallet_rpc_server.cpp" line="212"/> <source>RPC username/password is stored in file </source> - <translation>Username/password RPC conservate nel file </translation> + <translation>Username/password RPC conservato nel file </translation> </message> <message> <location filename="../src/wallet/wallet_rpc_server.cpp" line="1748"/> @@ -2654,19 +2665,19 @@ Outputs per *: </source> <message> <location filename="../src/wallet/wallet_rpc_server.cpp" line="1764"/> <source>Loading wallet...</source> - <translation>Caricando il portafoglio...</translation> + <translation>Sto caricando il portafoglio...</translation> </message> <message> <location filename="../src/wallet/wallet_rpc_server.cpp" line="1789"/> <location filename="../src/wallet/wallet_rpc_server.cpp" line="1814"/> <source>Storing wallet...</source> - <translation>Conservando il portafoglio...</translation> + <translation>Sto salvando il portafoglio...</translation> </message> <message> <location filename="../src/wallet/wallet_rpc_server.cpp" line="1791"/> <location filename="../src/wallet/wallet_rpc_server.cpp" line="1816"/> <source>Stored ok</source> - <translation>Conservato con successo</translation> + <translation>Salvato con successo</translation> </message> <message> <location filename="../src/wallet/wallet_rpc_server.cpp" line="1794"/> @@ -2686,7 +2697,7 @@ Outputs per *: </source> <message> <location filename="../src/wallet/wallet_rpc_server.cpp" line="1809"/> <source>Starting wallet rpc server</source> - <translation>Server RPC portafoglio in partenza</translation> + <translation>Server RPC portafoglio in avvio</translation> </message> <message> <location filename="../src/wallet/wallet_rpc_server.cpp" line="1811"/> @@ -2696,7 +2707,7 @@ Outputs per *: </source> <message> <location filename="../src/wallet/wallet_rpc_server.cpp" line="1820"/> <source>Failed to store wallet: </source> - <translation>Impossibile conservare portafoglio: </translation> + <translation>Impossibile salvare portafoglio: </translation> </message> </context> <context> @@ -2725,7 +2736,7 @@ Outputs per *: </source> <message> <location filename="../src/wallet/wallet_args.cpp" line="88"/> <source>Specify log file</source> - <translation>Specificare log file</translation> + <translation>Specificare file di log</translation> </message> <message> <location filename="../src/wallet/wallet_args.cpp" line="89"/> @@ -2745,12 +2756,12 @@ Outputs per *: </source> <message> <location filename="../src/wallet/wallet_args.cpp" line="172"/> <source>Logging to: </source> - <translation>Loggando in: </translation> + <translation>Sto salvando il Log in: </translation> </message> <message> <location filename="../src/wallet/wallet_args.cpp" line="173"/> <source>Logging to %s</source> - <translation>Loggando in %s</translation> + <translation>Sto salvando il Log in %s</translation> </message> <message> <location filename="../src/wallet/wallet_args.cpp" line="153"/> |