diff options
114 files changed, 2222 insertions, 1088 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 971c097ff..1f74f59e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -186,7 +186,7 @@ endif() # elseif(CMAKE_SYSTEM_NAME MATCHES ".*BSDI.*") # set(BSDI TRUE) -include_directories(external/easylogging++ src contrib/epee/include external "${CMAKE_BINARY_DIR}/version") +include_directories(external/easylogging++ src contrib/epee/include external) if(APPLE) include_directories(SYSTEM /usr/include/malloc) @@ -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) @@ -407,7 +408,7 @@ else() set(WARNINGS "${WARNINGS} -Wno-error=inline-asm") endif() else() - set(WARNINGS "${WARNINGS} -Wlogical-op -Wno-error=maybe-uninitialized") + set(WARNINGS "${WARNINGS} -Wlogical-op -Wno-error=maybe-uninitialized -Wno-error=cpp") endif() if(MINGW) set(WARNINGS "${WARNINGS} -Wno-error=unused-value -Wno-error=unused-but-set-variable") @@ -691,25 +692,17 @@ 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() - -function (treat_warnings_as_errors dirs) - foreach(dir ${ARGV}) - set_property(DIRECTORY ${dir} - APPEND PROPERTY COMPILE_FLAGS "-Werror") - endforeach() -endfunction() - -add_subdirectory(contrib) -add_subdirectory(src) - -treat_warnings_as_errors(contrib src) option(BUILD_TESTS "Build tests." OFF) @@ -717,7 +710,13 @@ if(BUILD_TESTS) add_subdirectory(tests) endif() +# warnings are cleared only for GCC on Linux +if (NOT (MINGW OR APPLE OR FREEBSD OR OPENBSD OR DRAGONFLY)) +add_compile_options("${WARNINGS_AS_ERRORS_FLAG}") # applies only to targets that follow +endif() +add_subdirectory(contrib) +add_subdirectory(src) if(BUILD_DOCUMENTATION) set(DOC_GRAPHS "YES" CACHE STRING "Create dependency graphs (needs graphviz)") @@ -11,6 +11,11 @@ Portions Copyright (c) 2012-2013, The Cryptonote developers - GitHub: [https://github.com/monero-project/monero](https://github.com/monero-project/monero) - IRC: [#monero-dev on Freenode](http://webchat.freenode.net/?randomnick=1&channels=%23monero-dev&prompt=1&uio=d4) +## Vulnerability Response + +- Our [Vulnerability Response Process](https://github.com/monero-project/meta/blob/master/VULNERABILITY_RESPONSE_PROCESS.md) encourages responsible disclosure +- We are also available via [HackerOne](https://hackerone.com/monero) + ## Build | Operating System | Processor | Status | @@ -89,18 +94,22 @@ If you want to help out, see [CONTRIBUTING](CONTRIBUTING.md) for a set of guidel See [Vulnerability Response Process](VULNERABILITY_RESPONSE_PROCESS.md). -## Monero software updates and consensus protocol changes (hard fork schedule) +## Monero software updates and Network Consensus Protocol Upgrade (hard fork schedule) -Monero uses a fixed-schedule hard fork mechanism to implement new features. This means that users of Monero (end users and service providers) need to run current versions and update their software on a regular schedule. Here is the current schedule, versions, and compatibility. +Monero uses a fixed-schedule network consensus protocol upgrade (hard fork) mechanism to implement new features. This means that users of Monero (end users and service providers) need to run current versions and upgrade their software on a regular schedule. Network consensus protocol upgrades occur during the months of March and September. Required software for these consensus protocol upgrades is available prior to the date of the consensus protocol upgrade. Please check the git repository prior to this date for the proper Monero software version. Below is the historical schedule and the projected schedule for the next upgrade. Dates are provided in the format YYYY-MM-DD. -| Fork Date | Consensus version | Minimum Monero Version | Recommended Monero Version | Details | -| ----------------- | ----------------- | ---------------------- | -------------------------- | ------------------ | -| 2016-09-21 | v3 | v0.9.4 | v0.10.0 | Splits coinbase into denominations | -| 2017-01-05 | v4 | v0.10.1 | v0.10.2.1 | Allow normal and RingCT transactions | -| 2017-04-15 | v5 | v0.10.3.0 | v0.10.3.1 | Adjusted minimum blocksize and fee algorithm | -| 2017-09-21 | v6 | Not determined as of 2017-03-27 | Not determined as of 2017-03-27 | Allow only RingCT transactions | +| Consensus Upgrade Block Height | Date | Consensus version | Minimum Monero Version | Recommended Monero Version | Details | +| ------------------------------ | -----------| ----------------- | ---------------------- | -------------------------- | ---------------------------------------------------------------------------------- | +| 1009827 | 2016-03-22 | v2 | v0.9.4 | v0.9.4 | Allow only >= ringsize 3, blocktime = 120 seconds, fee-free blocksize 60 kb | +| 1141317 | 2016-09-21 | v3 | v0.9.4 | v0.10.0 | Splits coinbase into denominations | +| 1220516 | 2017-01-05 | v4 | v0.10.1 | v0.10.2.1 | Allow normal and RingCT transactions | +| 1288616 | 2017-04-15 | v5 | v0.10.3.0 | v0.10.3.1 | Adjusted minimum blocksize and fee algorithm | +| 1400000 | 2017-09-16 | v6 | v0.11.0.0 | v0.11.0.0 | Allow only RingCT transactions, allow only >= ringsize 5 | +| XXXXXXX | 2018-03-XX | XX | XXXXXXXXX | XXXXXXXXX | XXXXXX + +X's indicate that these details have not been determined as of commit date, 2017-09-20. ## Installing Monero from a Package @@ -153,10 +162,12 @@ library archives (`.a`). | pkg-config | any | NO | `pkg-config` | `base-devel` | NO | | | Boost | 1.58 | NO | `libboost-all-dev` | `boost` | NO | C++ libraries | | OpenSSL | basically any | NO | `libssl-dev` | `openssl` | NO | sha256 sum | +| libzmq | 3.0.0 | NO | `libzmq3-dev` | `zeromq` | NO | ZeroMQ library | | libunbound | 1.4.16 | YES | `libunbound-dev` | `unbound` | NO | DNS resolver | | libminiupnpc | 2.0 | YES | `libminiupnpc-dev` | `miniupnpc` | YES | NAT punching | | libunwind | any | NO | `libunwind8-dev` | `libunwind` | YES | Stack traces | | liblzma | any | NO | `liblzma-dev` | `xz` | YES | For libunwind | +| libreadline | 6.3.0 | NO | `libreadline6-dev` | `readline` | YES | Input editing | | ldns | 1.6.17 | NO | `libldns-dev` | `ldns` | YES | SSL toolkit | | expat | 1.1 | NO | `libexpat1-dev` | `expat` | YES | XML parsing | | GTest | 1.5 | YES | `libgtest-dev`^ | `gtest` | YES | Test suite | @@ -184,6 +195,9 @@ invokes cmake commands as needed. this to be worthwhile, the machine should have one core and about 2GB of RAM available per thread. + *Note*: If cmake can not find zmq.hpp file on OS X, installing `zmq.hpp` from + https://github.com/zeromq/cppzmq to `/usr/local/include` should fix that error. + * The resulting executables can be found in `build/release/bin` * Add `PATH="$PATH:$HOME/monero/build/release/bin"` to `.profile` @@ -208,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: ``` @@ -223,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 @@ -238,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: @@ -280,11 +316,11 @@ application. To build for 64-bit Windows: - pacman -S mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-boost + pacman -S mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium To build for 32-bit Windows: - pacman -S mingw-w64-i686-toolchain make mingw-w64-i686-cmake mingw-w64-i686-boost + pacman -S mingw-w64-i686-toolchain make mingw-w64-i686-cmake mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-zeromq mingw-w64-i686-libsodium * Open the MingW shell via `MinGW-w64-Win64 Shell` shortcut on 64-bit Windows or `MinGW-w64-Win64 Shell` shortcut on 32-bit Windows. Note that if you are @@ -394,14 +430,6 @@ TAILS ships with a very restrictive set of firewall rules. Therefore, you need t `./monero-wallet-cli` -## Using readline - -While monerod and monero-wallet-cli do not use readline directly, most of the functionality can be obtained by running them via rlwrap. This allows command recall, edit capabilities, etc. It does not give autocompletion without an extra completion file, however. To use rlwrap, simply prepend `rlwrap` to the command line, eg: - -`rlwrap bin/monero-wallet-cli --wallet-file /path/to/wallet` - -Note: rlwrap will save things like your seed and private keys, if you supply them on prompt. You may want to not use rlwrap when you use simplewallet to restore from seed, etc. - # Debugging This section contains general instructions for debugging failed installs or problems encountered with Monero. First ensure you are running the latest version built from the github repo. diff --git a/VULNERABILITY_RESPONSE_PROCESS.md b/VULNERABILITY_RESPONSE_PROCESS.md deleted file mode 100644 index eea3a06e7..000000000 --- a/VULNERABILITY_RESPONSE_PROCESS.md +++ /dev/null @@ -1,143 +0,0 @@ -# Monero Vulnerability Response Process - -## Preamble - -Researchers/Hackers: while you research/hack, we ask that you please refrain from committing the following: -- Denial of Service / Active exploiting against the network -- Social Engineering of Monero staff or contractors -- Any physical or electronic attempts against Monero community property and/or data centers - -## I. Point of Contacts for Security Issues - -``` -ric@getmonero.org -BDA6 BD70 42B7 21C4 67A9 759D 7455 C5E3 C0CD CEB9 - -luigi1111@getmonero.org -8777 AB8F 778E E894 87A2 F8E7 F4AC A018 3641 E010 - -moneromooo.monero@gmail.com -48B0 8161 FBDA DFE3 93AD FC3E 686F 0745 4D6C EFC3 -``` - -## II. Security Response Team - -- fluffypony -- luigi1111 -- moneromooo - -## III. Incident Response - -1. Researcher submits report via one or both of two methods: - - a. Email - - b. [HackerOne](https://hackerone.com/monero) - -2. Response Team designates a Response Manager who is in charge of the particular report based on availability and/or knowledge-set - -3. In no more than 3 working days, Response Team should gratefully respond to researcher using only encrypted, secure channels - -4. Response Manager makes inquiries to satisfy any needed information to confirm if submission is indeed a vulnerability - - a. If submission proves to be vulnerable, proceed to next step - - b. If not vulnerable: - - i. Response Manager responds with reasons why submission is not a vulnerability - - ii. Response Manager moves discussion to a new or existing ticket on GitHub if necessary - -5. If over email, Response Manager opens a HackerOne issue for new submission - -6. Establish severity of vulnerability: - - a. HIGH: impacts network as a whole, has potential to break entire network, results in the loss of monero, or is on a scale of great catastrophe - - b. MEDIUM: impacts individual nodes, wallets, or must be carefully exploited - - c. LOW: is not easily exploitable - -7. Respond according to the severity of the vulnerability: - - a. HIGH severities must be notified on website and reddit /r/Monero within 3 working days of classification - - i. The notification should list appropriate steps for users to take, if any - - ii. The notification must not include any details that could suggest an exploitation path - - iii. The latter takes precedence over the former - - b. MEDIUM and HIGH severities will require a Point Release - - c. LOW severities will be addressed in the next Regular Release - -8. Response Team applies appropriate patch(es) - - a. Response Manager designates a PRIVATE git "hotfix branch" to work in - - b. Patches are reviewed with the researcher - - c. Any messages associated with PUBLIC commits during the time of review should not make reference to the security nature of the PRIVATE branch or its commits - - d. Vulnerability announcement is drafted - - i. Include the severity of the vulnerability - - ii. Include all vulnerable systems/apps/code - - iii. Include solutions (if any) if patch cannot be applied - - e. Release date is discussed - -9. At release date, Response Team coordinates with developers to finalize update: - - a. Response Manager propagates the "hotfix branch" to trunk - - b. Response Manager includes vulnerability announcement draft in release notes - - c. Proceed with the Point or Regular Release - -## IV. Post-release Disclosure Process - -1. Response Team has 90 days to fulfill all points within section III - -2. If the Incident Response process in section III is successfully completed: - - a. Response Manager contacts researcher and asks if researcher wishes for credit - - b. Finalize vulnerability announcement draft and include the following: - - i. Project name and URL - - ii. Versions known to be affected - - iii. Versions known to be not affected (for example, the vulnerable code was introduced in a recent version, and older versions are therefore unaffected) - - iv. Versions not checked - - v. Type of vulnerability and its impact - - vi. If already obtained or applicable, a CVE-ID - - vii. The planned, coordinated release date - - viii. Mitigating factors (for example, the vulnerability is only exposed in uncommon, non-default configurations) - - ix. Workarounds (configuration changes users can make to reduce their exposure to the vulnerability) - - x. If applicable, credits to the original reporter - - c. Release finalized vulnerability announcement on website and reddit /r/Monero - - d. For HIGH severities, release finalized vulnerability announcement on well-known mailing lists: - - i. oss-security@lists.openwall.com - - ii. bugtraq@securityfocus.com - - e. If applicable, developers request a CVE-ID - - i. The commit that applied the fix is made reference too in a future commit and includes a CVE-ID - -3. If the Incident Response process in section III is *not* successfully completed: - - a. Response Team and developers organize an IRC meeting to discuss why/what points in section III were not resolved and how the team can resolve them in the future - - b. Any developer meetings immediately following the incident should include points made in section V - - c. If disputes arise about whether or when to disclose information about a vulnerability, the Response Team will publicly discuss the issue via IRC and attempt to reach consensus - - d. If consensus on a timely disclosure is not met (no later than 90 days), the researcher (after 90 days) has every right to expose the vulnerability to the public - -## V. Incident Analysis - -1. Isolate codebase - - a. Response Team and developers should coordinate to work on the following: - - i. Problematic implementation of classes/libraries/functions, etc. - - ii. Focus on apps/distro packaging, etc. - - iii. Operator/config error, etc. - -2. Auditing - - a. Response Team and developers should coordinate to work on the following: - - i. Auditing of problem area(s) as discussed in point 1 - - ii. Generate internal reports and store for future reference - - iii. If results are not sensitive, share with the public via IRC or GitHub - -3. Response Team has 45 days following completion of section III to ensure completion of section V - -## VI. Resolutions - -Any further questions or resolutions regarding the incident(s) between the researcher and response + development team after public disclosure can be addressed via the following: - -- [GitHub](https://github.com/monero-project/monero/issues/) -- [HackerOne](https://hackerone.com/monero) -- [Reddit /r/Monero](https://reddit.com/r/Monero/) -- IRC -- Email - -## VII. Continuous Improvement - -1. Response Team and developers should hold annual meetings to review the previous year's incidents - -2. Response Team or designated person(s) should give a brief presentation, including: - - a. Areas of Monero affected by the incidents - - b. Any network downtime or monetary cost (if any) of the incidents - - c. Ways in which the incidents could have been avoided (if any) - - d. How effective this process was in dealing with the incidents - -3. After the presentation, Response Team and developers should discuss: - - a. Potential changes to development processes to reduce future incidents - - b. Potential changes to this process to improve future responses diff --git a/cmake/FindMiniupnpc.cmake b/cmake/FindMiniupnpc.cmake index 77675db48..ad2004afc 100644 --- a/cmake/FindMiniupnpc.cmake +++ b/cmake/FindMiniupnpc.cmake @@ -46,13 +46,13 @@ IF(MINIUPNPC_FOUND) file(STRINGS "${MINIUPNP_INCLUDE_DIR}/miniupnpc.h" MINIUPNPC_API_VERSION_STR REGEX "^#define[\t ]+MINIUPNPC_API_VERSION[\t ]+[0-9]+") if(MINIUPNPC_API_VERSION_STR MATCHES "^#define[\t ]+MINIUPNPC_API_VERSION[\t ]+([0-9]+)") set(MINIUPNPC_API_VERSION "${CMAKE_MATCH_1}") + if (${MINIUPNPC_API_VERSION} GREATER "10" OR ${MINIUPNPC_API_VERSION} EQUAL "10") + message(STATUS "Found miniupnpc API version " ${MINIUPNPC_API_VERSION}) + set(MINIUPNP_FOUND true) + set(MINIUPNPC_VERSION_1_7_OR_HIGHER true) + endif() endif() - if (${MINIUPNPC_API_VERSION} GREATER "10" OR ${MINIUPNPC_API_VERSION} EQUAL "10") - message(STATUS "Found miniupnpc API version " ${MINIUPNPC_API_VERSION}) - set(MINIUPNP_FOUND true) - set(MINIUPNPC_VERSION_1_7_OR_HIGHER true) - endif() ENDIF() mark_as_advanced(MINIUPNP_INCLUDE_DIR MINIUPNP_LIBRARY MINIUPNP_STATIC_LIBRARY) diff --git a/contrib/epee/include/misc_log_ex.h b/contrib/epee/include/misc_log_ex.h index ec4bcbe2d..d351b024d 100644 --- a/contrib/epee/include/misc_log_ex.h +++ b/contrib/epee/include/misc_log_ex.h @@ -52,6 +52,7 @@ #include "easylogging++.h" #define MONERO_DEFAULT_LOG_CATEGORY "default" +#define MAX_LOG_FILE_SIZE 104850000 // 100 MB - 7600 bytes #define MCFATAL(cat,x) CLOG(FATAL,cat) << x #define MCERROR(cat,x) CLOG(ERROR,cat) << x @@ -123,7 +124,7 @@ #endif std::string mlog_get_default_log_path(const char *default_filename); -void mlog_configure(const std::string &filename_base, bool console); +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); void mlog_set_log_level(int level); void mlog_set_log(const char *log); diff --git a/contrib/epee/include/net/abstract_tcp_server2.h b/contrib/epee/include/net/abstract_tcp_server2.h index ca58d5467..03f143fe4 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.h +++ b/contrib/epee/include/net/abstract_tcp_server2.h @@ -281,8 +281,6 @@ namespace net_utils bool is_thread_worker(); - bool cleanup_connections(); - /// The io_service used to perform asynchronous operations. std::unique_ptr<boost::asio::io_service> m_io_service_local_instance; boost::asio::io_service& io_service_; @@ -309,7 +307,7 @@ namespace net_utils connection_ptr new_connection_; boost::mutex connections_mutex; - std::deque<std::pair<boost::system_time, connection_ptr>> connections_; + std::set<connection_ptr> connections_; }; // class <>boosted_tcp_server diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl index 61276e761..76988a26e 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -54,8 +54,6 @@ #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "net" -#define CONNECTION_CLEANUP_TIME 30 // seconds - PRAGMA_WARNING_PUSH namespace epee { @@ -808,7 +806,6 @@ POP_WARNINGS m_threads_count = threads_count; m_main_thread_id = boost::this_thread::get_id(); MLOG_SET_THREAD_NAME("[SRV_MAIN]"); - add_idle_handler(boost::bind(&boosted_tcp_server::cleanup_connections, this), 5000); while(!m_stop_signal_sent) { @@ -898,7 +895,7 @@ POP_WARNINGS connections_mutex.lock(); for (auto &c: connections_) { - c.second->cancel(); + c->cancel(); } connections_.clear(); connections_mutex.unlock(); @@ -907,19 +904,6 @@ POP_WARNINGS } //--------------------------------------------------------------------------------- template<class t_protocol_handler> - bool boosted_tcp_server<t_protocol_handler>::cleanup_connections() - { - connections_mutex.lock(); - boost::system_time cutoff = boost::get_system_time() - boost::posix_time::seconds(CONNECTION_CLEANUP_TIME); - while (!connections_.empty() && connections_.front().first < cutoff) - { - connections_.pop_front(); - } - connections_mutex.unlock(); - return true; - } - //--------------------------------------------------------------------------------- - template<class t_protocol_handler> bool boosted_tcp_server<t_protocol_handler>::is_stop_signal_sent() { return m_stop_signal_sent; @@ -958,9 +942,10 @@ POP_WARNINGS connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_config, m_sock_count, m_sock_number, m_pfilter, m_connection_type) ); connections_mutex.lock(); - connections_.push_back(std::make_pair(boost::get_system_time(), new_connection_l)); + connections_.insert(new_connection_l); MDEBUG("connections_ size now " << connections_.size()); connections_mutex.unlock(); + epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ CRITICAL_REGION_LOCAL(connections_mutex); connections_.erase(new_connection_l); }); boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket(); ////////////////////////////////////////////////////////////////////////// @@ -1038,6 +1023,10 @@ POP_WARNINGS _dbg3("Connected success to " << adr << ':' << port); + // start adds the connection to the config object's list, so we don't need to have it locally anymore + connections_mutex.lock(); + connections_.erase(new_connection_l); + connections_mutex.unlock(); bool r = new_connection_l->start(false, 1 < m_threads_count); if (r) { @@ -1062,9 +1051,10 @@ POP_WARNINGS TRY_ENTRY(); connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_config, m_sock_count, m_sock_number, m_pfilter, m_connection_type) ); connections_mutex.lock(); - connections_.push_back(std::make_pair(boost::get_system_time(), new_connection_l)); + connections_.insert(new_connection_l); MDEBUG("connections_ size now " << connections_.size()); connections_mutex.unlock(); + epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ CRITICAL_REGION_LOCAL(connections_mutex); connections_.erase(new_connection_l); }); boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket(); ////////////////////////////////////////////////////////////////////////// @@ -1113,6 +1103,11 @@ POP_WARNINGS { _dbg3("[sock " << new_connection_l->socket().native_handle() << "] Connected success to " << adr << ':' << port << " from " << lep.address().to_string() << ':' << lep.port()); + + // start adds the connection to the config object's list, so we don't need to have it locally anymore + connections_mutex.lock(); + connections_.erase(new_connection_l); + connections_mutex.unlock(); bool r = new_connection_l->start(false, 1 < m_threads_count); if (r) { diff --git a/contrib/epee/include/net/http_base.h b/contrib/epee/include/net/http_base.h index e5aa06cb4..144acad9d 100644 --- a/contrib/epee/include/net/http_base.h +++ b/contrib/epee/include/net/http_base.h @@ -155,7 +155,8 @@ namespace net_utils http_request_info():m_http_method(http_method_unknown), m_http_ver_hi(0), m_http_ver_lo(0), - m_have_to_block(false) + m_have_to_block(false), + m_full_request_buf_size(0) {} http_method m_http_method; 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..df83517ff 100644 --- a/contrib/epee/include/net/net_utils_base.h +++ b/contrib/epee/include/net/net_utils_base.h @@ -71,6 +71,9 @@ namespace net_utils } uint64_t m_host_id; uint64_t m_full_id; + + protected: + virtual ~network_address_base() {} }; struct ipv4_network_address: public network_address_base { 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/mlog.cpp b/contrib/epee/src/mlog.cpp index a3f38e677..964ba41df 100644 --- a/contrib/epee/src/mlog.cpp +++ b/contrib/epee/src/mlog.cpp @@ -111,7 +111,7 @@ static const char *get_default_categories(int level) return categories; } -void mlog_configure(const std::string &filename_base, bool console) +void mlog_configure(const std::string &filename_base, bool console, const std::size_t max_log_file_size) { el::Configurations c; c.setGlobally(el::ConfigurationType::Filename, filename_base); @@ -121,7 +121,7 @@ void mlog_configure(const std::string &filename_base, bool console) log_format = MLOG_BASE_FORMAT; c.setGlobally(el::ConfigurationType::Format, log_format); c.setGlobally(el::ConfigurationType::ToStandardOutput, console ? "true" : "false"); - c.setGlobally(el::ConfigurationType::MaxLogFileSize, "104850000"); // 100 MB - 7600 bytes + c.setGlobally(el::ConfigurationType::MaxLogFileSize, std::to_string(max_log_file_size)); el::Loggers::setDefaultConfigurations(c, true); el::Loggers::addFlag(el::LoggingFlag::HierarchicalLogging); 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/src/CMakeLists.txt b/src/CMakeLists.txt index e3cb7cfd6..57ff28bfc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -96,9 +96,13 @@ function (monero_add_library name) PRIVATE $<TARGET_PROPERTY:${name},INTERFACE_COMPILE_DEFINITIONS>) endfunction () +set_source_files_properties(${CMAKE_BINARY_DIR}/version.cpp PROPERTIES GENERATED ON) +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/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index 85a494ce7..838385e8a 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -711,7 +711,7 @@ public: * * @return true if we started the batch, false if already started */ - virtual bool batch_start(uint64_t batch_num_blocks=0) = 0; + virtual bool batch_start(uint64_t batch_num_blocks=0, uint64_t batch_bytes=0) = 0; /** * @brief ends a batch transaction diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index b6978bdc4..985244f6b 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -548,7 +548,7 @@ bool BlockchainLMDB::need_resize(uint64_t threshold_size) const #endif } -void BlockchainLMDB::check_and_resize_for_batch(uint64_t batch_num_blocks) +void BlockchainLMDB::check_and_resize_for_batch(uint64_t batch_num_blocks, uint64_t batch_bytes) { LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L1("[" << __func__ << "] " << "checking DB size"); @@ -557,7 +557,7 @@ void BlockchainLMDB::check_and_resize_for_batch(uint64_t batch_num_blocks) uint64_t increase_size = 0; if (batch_num_blocks > 0) { - threshold_size = get_estimated_batch_size(batch_num_blocks); + threshold_size = get_estimated_batch_size(batch_num_blocks, batch_bytes); LOG_PRINT_L1("calculated batch size: " << threshold_size); // The increased DB size could be a multiple of threshold_size, a fixed @@ -580,7 +580,7 @@ void BlockchainLMDB::check_and_resize_for_batch(uint64_t batch_num_blocks) } } -uint64_t BlockchainLMDB::get_estimated_batch_size(uint64_t batch_num_blocks) const +uint64_t BlockchainLMDB::get_estimated_batch_size(uint64_t batch_num_blocks, uint64_t batch_bytes) const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); uint64_t threshold_size = 0; @@ -607,6 +607,11 @@ uint64_t BlockchainLMDB::get_estimated_batch_size(uint64_t batch_num_blocks) con uint64_t total_block_size = 0; LOG_PRINT_L1("[" << __func__ << "] " << "m_height: " << m_height << " block_start: " << block_start << " block_stop: " << block_stop); size_t avg_block_size = 0; + if (batch_bytes) + { + avg_block_size = batch_bytes / batch_num_blocks; + goto estim; + } if (m_height == 0) { LOG_PRINT_L1("No existing blocks to check for average block size"); @@ -635,6 +640,7 @@ uint64_t BlockchainLMDB::get_estimated_batch_size(uint64_t batch_num_blocks) con avg_block_size = total_block_size / num_blocks_used; LOG_PRINT_L1("average block size across recent " << num_blocks_used << " blocks: " << avg_block_size); } +estim: if (avg_block_size < min_block_size) avg_block_size = min_block_size; LOG_PRINT_L1("estimated average block size for batch: " << avg_block_size); @@ -2420,8 +2426,8 @@ bool BlockchainLMDB::for_blocks_range(const uint64_t& h1, const uint64_t& h2, st MDB_cursor_op op; if (h1) { - MDB_val_set(k, h1); - op = MDB_SET; + k = MDB_val{sizeof(h1), (void*)&h1}; + op = MDB_SET; } else { op = MDB_FIRST; @@ -2540,7 +2546,7 @@ bool BlockchainLMDB::for_all_outputs(std::function<bool(uint64_t amount, const c } // batch_num_blocks: (optional) Used to check if resize needed before batch transaction starts. -bool BlockchainLMDB::batch_start(uint64_t batch_num_blocks) +bool BlockchainLMDB::batch_start(uint64_t batch_num_blocks, uint64_t batch_bytes) { LOG_PRINT_L3("BlockchainLMDB::" << __func__); if (! m_batch_transactions) @@ -2554,7 +2560,7 @@ bool BlockchainLMDB::batch_start(uint64_t batch_num_blocks) check_open(); m_writer = boost::this_thread::get_id(); - check_and_resize_for_batch(batch_num_blocks); + check_and_resize_for_batch(batch_num_blocks, batch_bytes); m_write_batch_txn = new mdb_txn_safe(); diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h index 90274b904..98571a7f8 100644 --- a/src/blockchain_db/lmdb/db_lmdb.h +++ b/src/blockchain_db/lmdb/db_lmdb.h @@ -264,7 +264,7 @@ public: ); virtual void set_batch_transactions(bool batch_transactions); - virtual bool batch_start(uint64_t batch_num_blocks=0); + virtual bool batch_start(uint64_t batch_num_blocks=0, uint64_t batch_bytes=0); virtual void batch_commit(); virtual void batch_stop(); virtual void batch_abort(); @@ -294,8 +294,8 @@ private: void do_resize(uint64_t size_increase=0); bool need_resize(uint64_t threshold_size=0) const; - void check_and_resize_for_batch(uint64_t batch_num_blocks); - uint64_t get_estimated_batch_size(uint64_t batch_num_blocks) const; + void check_and_resize_for_batch(uint64_t batch_num_blocks, uint64_t batch_bytes); + uint64_t get_estimated_batch_size(uint64_t batch_num_blocks, uint64_t batch_bytes) const; virtual void add_block( const block& blk , const size_t& block_size diff --git a/src/blockchain_utilities/CMakeLists.txt b/src/blockchain_utilities/CMakeLists.txt index ffdaad4af..0eaf71084 100644 --- a/src/blockchain_utilities/CMakeLists.txt +++ b/src/blockchain_utilities/CMakeLists.txt @@ -77,6 +77,7 @@ target_link_libraries(blockchain_import cryptonote_core blockchain_db p2p + version epee ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} @@ -89,8 +90,6 @@ if(ARCH_WIDTH) PUBLIC -DARCH_WIDTH=${ARCH_WIDTH}) endif() -add_dependencies(blockchain_import - version) set_property(TARGET blockchain_import PROPERTY OUTPUT_NAME "monero-blockchain-import") @@ -104,6 +103,7 @@ target_link_libraries(blockchain_export cryptonote_core blockchain_db p2p + version epee ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} @@ -111,8 +111,6 @@ target_link_libraries(blockchain_export ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_LIBRARIES}) -add_dependencies(blockchain_export - version) set_property(TARGET blockchain_export PROPERTY OUTPUT_NAME "monero-blockchain-export") diff --git a/src/blockchain_utilities/blockchain_import.cpp b/src/blockchain_utilities/blockchain_import.cpp index 635a70b10..d6302ea1d 100644 --- a/src/blockchain_utilities/blockchain_import.cpp +++ b/src/blockchain_utilities/blockchain_import.cpp @@ -230,11 +230,22 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path return false; } + uint64_t start_height = 1, seek_height; + if (opt_resume) + start_height = core.get_blockchain_storage().get_current_blockchain_height(); + + seek_height = start_height; BootstrapFile bootstrap; + streampos pos; // BootstrapFile bootstrap(import_file_path); - uint64_t total_source_blocks = bootstrap.count_blocks(import_file_path); + uint64_t total_source_blocks = bootstrap.count_blocks(import_file_path, pos, seek_height); MINFO("bootstrap file last block number: " << total_source_blocks-1 << " (zero-based height) total blocks: " << total_source_blocks); + if (total_source_blocks-1 <= start_height) + { + return false; + } + std::cout << ENDL; std::cout << "Preparing to read blocks..." << ENDL; std::cout << ENDL; @@ -259,11 +270,7 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path block b; transaction tx; int quit = 0; - uint64_t bytes_read = 0; - - uint64_t start_height = 1; - if (opt_resume) - start_height = core.get_blockchain_storage().get_current_blockchain_height(); + uint64_t bytes_read; // Note that a new blockchain will start with block number 0 (total blocks: 1) // due to genesis block being added at initialization. @@ -280,18 +287,35 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path bool use_batch = opt_batch && !opt_verify; - if (use_batch) - core.get_blockchain_storage().get_db().batch_start(db_batch_size); - MINFO("Reading blockchain from bootstrap file..."); std::cout << ENDL; std::list<block_complete_entry> blocks; - // Within the loop, we skip to start_height before we start adding. - // TODO: Not a bottleneck, but we can use what's done in count_blocks() and - // only do the chunk size reads, skipping the chunk content reads until we're - // at start_height. + // Skip to start_height before we start adding. + { + bool q2 = false; + import_file.seekg(pos); + bytes_read = bootstrap.count_bytes(import_file, start_height-seek_height, h, q2); + if (q2) + { + quit = 2; + goto quitting; + } + h = start_height; + } + + if (use_batch) + { + uint64_t bytes, h2; + bool q2; + pos = import_file.tellg(); + bytes = bootstrap.count_bytes(import_file, db_batch_size, h2, q2); + if (import_file.eof()) + import_file.clear(); + import_file.seekg(pos); + core.get_blockchain_storage().get_db().batch_start(db_batch_size, bytes); + } while (! quit) { uint32_t chunk_size; @@ -344,11 +368,6 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path bytes_read += chunk_size; MDEBUG("Total bytes read: " << bytes_read); - if (h + NUM_BLOCKS_PER_CHUNK < start_height + 1) - { - h += NUM_BLOCKS_PER_CHUNK; - continue; - } if (h > block_stop) { std::cout << refresh_string << "block " << h-1 @@ -456,11 +475,16 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path { if ((h-1) % db_batch_size == 0) { + uint64_t bytes, h2; + bool q2; std::cout << refresh_string; // zero-based height std::cout << ENDL << "[- batch commit at height " << h-1 << " -]" << ENDL; core.get_blockchain_storage().get_db().batch_stop(); - core.get_blockchain_storage().get_db().batch_start(db_batch_size); + pos = import_file.tellg(); + bytes = bootstrap.count_bytes(import_file, db_batch_size, h2, q2); + import_file.seekg(pos); + core.get_blockchain_storage().get_db().batch_start(db_batch_size, bytes); std::cout << ENDL; core.get_blockchain_storage().get_db().show_stats(); } @@ -477,6 +501,7 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path } } // while +quitting: import_file.close(); if (opt_verify) diff --git a/src/blockchain_utilities/bootstrap_file.cpp b/src/blockchain_utilities/bootstrap_file.cpp index 2b1a5d6c7..a004d3547 100644 --- a/src/blockchain_utilities/bootstrap_file.cpp +++ b/src/blockchain_utilities/bootstrap_file.cpp @@ -375,39 +375,15 @@ uint64_t BootstrapFile::seek_to_first_chunk(std::ifstream& import_file) return full_header_size; } -uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) +uint64_t BootstrapFile::count_bytes(std::ifstream& import_file, uint64_t blocks, uint64_t& h, bool& quit) { - boost::filesystem::path raw_file_path(import_file_path); - boost::system::error_code ec; - if (!boost::filesystem::exists(raw_file_path, ec)) - { - MFATAL("bootstrap file not found: " << raw_file_path); - throw std::runtime_error("Aborting"); - } - std::ifstream import_file; - import_file.open(import_file_path, std::ios_base::binary | std::ifstream::in); - - uint64_t h = 0; - if (import_file.fail()) - { - MFATAL("import_file.open() fail"); - throw std::runtime_error("Aborting"); - } - - uint64_t full_header_size; // 4 byte magic + length of header structures - full_header_size = seek_to_first_chunk(import_file); - - MINFO("Scanning blockchain from bootstrap file..."); - block b; - bool quit = false; uint64_t bytes_read = 0; - int progress_interval = 10; - + uint32_t chunk_size; + char buf1[sizeof(chunk_size)]; std::string str1; - char buf1[2048]; - while (! quit) + h = 0; + while (1) { - uint32_t chunk_size; import_file.read(buf1, sizeof(chunk_size)); if (!import_file) { std::cout << refresh_string; @@ -415,15 +391,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) quit = true; break; } - h += NUM_BLOCKS_PER_CHUNK; - if ((h-1) % progress_interval == 0) - { - std::cout << "\r" << "block height: " << h-1 << - " " << - std::flush; - } bytes_read += sizeof(chunk_size); - str1.assign(buf1, sizeof(chunk_size)); if (! ::serialization::parse_binary(str1, chunk_size)) throw std::runtime_error("Error in deserialization of chunk_size"); @@ -456,6 +424,64 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) throw std::runtime_error("Aborting"); } bytes_read += chunk_size; + h += NUM_BLOCKS_PER_CHUNK; + if (h >= blocks) + break; + } + return bytes_read; +} + +uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) +{ + streampos dummy_pos; + uint64_t dummy_height = 0; + return count_blocks(import_file_path, dummy_pos, dummy_height); +} + +// If seek_height is non-zero on entry, return a stream position <= this height when finished. +// And return the actual height corresponding to this position. Allows the caller to locate its +// starting position without having to reread the entire file again. +uint64_t BootstrapFile::count_blocks(const std::string& import_file_path, streampos &start_pos, uint64_t& seek_height) +{ + boost::filesystem::path raw_file_path(import_file_path); + boost::system::error_code ec; + if (!boost::filesystem::exists(raw_file_path, ec)) + { + MFATAL("bootstrap file not found: " << raw_file_path); + throw std::runtime_error("Aborting"); + } + std::ifstream import_file; + import_file.open(import_file_path, std::ios_base::binary | std::ifstream::in); + + uint64_t start_height = seek_height; + uint64_t h = 0; + if (import_file.fail()) + { + MFATAL("import_file.open() fail"); + throw std::runtime_error("Aborting"); + } + + uint64_t full_header_size; // 4 byte magic + length of header structures + full_header_size = seek_to_first_chunk(import_file); + + MINFO("Scanning blockchain from bootstrap file..."); + bool quit = false; + uint64_t bytes_read = 0, blocks; + int progress_interval = 10; + + while (! quit) + { + if (start_height && h + progress_interval >= start_height - 1) + { + start_height = 0; + start_pos = import_file.tellg(); + seek_height = h; + } + bytes_read += count_bytes(import_file, progress_interval, blocks, quit); + h += blocks; + std::cout << "\r" << "block height: " << h-1 << + " " << + std::flush; // std::cout << refresh_string; MDEBUG("Number bytes scanned: " << bytes_read); diff --git a/src/blockchain_utilities/bootstrap_file.h b/src/blockchain_utilities/bootstrap_file.h index 1a646b54b..c3969a357 100644 --- a/src/blockchain_utilities/bootstrap_file.h +++ b/src/blockchain_utilities/bootstrap_file.h @@ -56,6 +56,8 @@ class BootstrapFile { public: + uint64_t count_bytes(std::ifstream& import_file, uint64_t blocks, uint64_t& h, bool& quit); + uint64_t count_blocks(const std::string& dir_path, streampos& start_pos, uint64_t& seek_height); uint64_t count_blocks(const std::string& dir_path); uint64_t seek_to_first_chunk(std::ifstream& import_file); 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/CMakeLists.txt b/src/common/CMakeLists.txt index 19d90253b..50887e35c 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -47,6 +47,7 @@ endif() set(common_headers) set(common_private_headers + apply_permutation.h base58.h boost_serialization_helper.h command_line.h diff --git a/src/common/apply_permutation.h b/src/common/apply_permutation.h new file mode 100644 index 000000000..4fd952686 --- /dev/null +++ b/src/common/apply_permutation.h @@ -0,0 +1,68 @@ +// Copyright (c) 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. +// +// Most of this file is originally copyright (c) 2017 Raymond Chen, Microsoft +// This algorithm is adapted from Raymond Chen's code: +// https://blogs.msdn.microsoft.com/oldnewthing/20170109-00/?p=95145 + +#include <vector> +#include <functional> +#include "misc_log_ex.h" + +namespace tools +{ + +template<typename F> +void apply_permutation(std::vector<size_t> permutation, const F &swap) +{ + //sanity check + for (size_t n = 0; n < permutation.size(); ++n) + CHECK_AND_ASSERT_THROW_MES(std::find(permutation.begin(), permutation.end(), n) != permutation.end(), "Bad permutation"); + + for (size_t i = 0; i < permutation.size(); ++i) + { + size_t current = i; + while (i != permutation[current]) + { + size_t next = permutation[current]; + swap(current, next); + permutation[current] = current; + current = next; + } + permutation[current] = current; + } +} + +template<typename T> +void apply_permutation(const std::vector<size_t> &permutation, std::vector<T> &v) +{ + CHECK_AND_ASSERT_THROW_MES(permutation.size() == v.size(), "Mismatched vector sizes"); + apply_permutation(permutation, [&v](size_t i0, size_t i1){ std::swap(v[i0], v[i1]); }); +} + +} diff --git a/src/common/base58.cpp b/src/common/base58.cpp index 64cb7c0de..941373443 100644 --- a/src/common/base58.cpp +++ b/src/common/base58.cpp @@ -111,13 +111,13 @@ namespace tools uint64_t res = 0; switch (9 - size) { - case 1: res |= *data++; - case 2: res <<= 8; res |= *data++; - case 3: res <<= 8; res |= *data++; - case 4: res <<= 8; res |= *data++; - case 5: res <<= 8; res |= *data++; - case 6: res <<= 8; res |= *data++; - case 7: res <<= 8; res |= *data++; + case 1: res |= *data++; /* FALLTHRU */ + case 2: res <<= 8; res |= *data++; /* FALLTHRU */ + case 3: res <<= 8; res |= *data++; /* FALLTHRU */ + case 4: res <<= 8; res |= *data++; /* FALLTHRU */ + case 5: res <<= 8; res |= *data++; /* FALLTHRU */ + case 6: res <<= 8; res |= *data++; /* FALLTHRU */ + case 7: res <<= 8; res |= *data++; /* FALLTHRU */ case 8: res <<= 8; res |= *data; break; default: assert(false); } diff --git a/src/common/dns_utils.cpp b/src/common/dns_utils.cpp index 57c856597..1310b8bfd 100644 --- a/src/common/dns_utils.cpp +++ b/src/common/dns_utils.cpp @@ -27,8 +27,6 @@ // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "common/dns_utils.h" -#include "common/i18n.h" -#include "cryptonote_basic/cryptonote_basic_impl.h" // check local first (in the event of static or in-source compilation of libunbound) #include "unbound.h" @@ -326,8 +324,6 @@ bool DNSResolver::check_address_syntax(const char *addr) const namespace dns_utils { -const char *tr(const char *str) { return i18n_translate(str, "tools::dns_utils"); } - //----------------------------------------------------------------------- // TODO: parse the string in a less stupid way, probably with regex std::string address_from_txt_record(const std::string& s) diff --git a/src/common/util.cpp b/src/common/util.cpp index 046961b06..74a6babf1 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -39,11 +39,13 @@ using namespace epee; #include "net/http_client.h" // epee::net_utils::... #ifdef WIN32 -#include <windows.h> -#include <shlobj.h> -#include <strsafe.h> + #include <windows.h> + #include <shlobj.h> + #include <strsafe.h> #else -#include <sys/utsname.h> + #include <sys/file.h> + #include <sys/utsname.h> + #include <sys/stat.h> #endif #include <boost/filesystem.hpp> #include <boost/asio.hpp> @@ -53,7 +55,12 @@ namespace tools { std::function<void(int)> signal_handler::m_handler; - std::unique_ptr<std::FILE, tools::close_file> create_private_file(const std::string& name) + private_file::private_file() noexcept : m_handle(), m_filename() {} + + private_file::private_file(std::FILE* handle, std::string&& filename) noexcept + : m_handle(handle), m_filename(std::move(filename)) {} + + private_file private_file::create(std::string name) { #ifdef WIN32 struct close_handle @@ -70,17 +77,17 @@ namespace tools const bool fail = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, std::addressof(temp)) == 0; process.reset(temp); if (fail) - return nullptr; + return {}; } DWORD sid_size = 0; GetTokenInformation(process.get(), TokenOwner, nullptr, 0, std::addressof(sid_size)); if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) - return nullptr; + return {}; std::unique_ptr<char[]> sid{new char[sid_size]}; if (!GetTokenInformation(process.get(), TokenOwner, sid.get(), sid_size, std::addressof(sid_size))) - return nullptr; + return {}; const PSID psid = reinterpret_cast<const PTOKEN_OWNER>(sid.get())->Owner; const DWORD daclSize = @@ -88,17 +95,17 @@ namespace tools const std::unique_ptr<char[]> dacl{new char[daclSize]}; if (!InitializeAcl(reinterpret_cast<PACL>(dacl.get()), daclSize, ACL_REVISION)) - return nullptr; + return {}; if (!AddAccessAllowedAce(reinterpret_cast<PACL>(dacl.get()), ACL_REVISION, (READ_CONTROL | FILE_GENERIC_READ | DELETE), psid)) - return nullptr; + return {}; SECURITY_DESCRIPTOR descriptor{}; if (!InitializeSecurityDescriptor(std::addressof(descriptor), SECURITY_DESCRIPTOR_REVISION)) - return nullptr; + return {}; if (!SetSecurityDescriptorDacl(std::addressof(descriptor), true, reinterpret_cast<PACL>(dacl.get()), false)) - return nullptr; + return {}; SECURITY_ATTRIBUTES attributes{sizeof(SECURITY_ATTRIBUTES), std::addressof(descriptor), false}; std::unique_ptr<void, close_handle> file{ @@ -106,7 +113,7 @@ namespace tools name.c_str(), GENERIC_WRITE, FILE_SHARE_READ, std::addressof(attributes), - CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, + CREATE_NEW, (FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE), nullptr ) }; @@ -121,22 +128,49 @@ namespace tools { _close(fd); } - return {real_file, tools::close_file{}}; + return {real_file, std::move(name)}; } } #else - const int fd = open(name.c_str(), (O_RDWR | O_EXCL | O_CREAT), S_IRUSR); - if (0 <= fd) + const int fdr = open(name.c_str(), (O_RDONLY | O_CREAT), S_IRUSR); + if (0 <= fdr) { - std::FILE* file = fdopen(fd, "w"); - if (!file) + struct stat rstats = {}; + if (fstat(fdr, std::addressof(rstats)) != 0) { - close(fd); + close(fdr); + return {}; + } + fchmod(fdr, (S_IRUSR | S_IWUSR)); + const int fdw = open(name.c_str(), O_RDWR); + fchmod(fdr, rstats.st_mode); + close(fdr); + + if (0 <= fdw) + { + struct stat wstats = {}; + if (fstat(fdw, std::addressof(wstats)) == 0 && + rstats.st_dev == wstats.st_dev && rstats.st_ino == wstats.st_ino && + flock(fdw, (LOCK_EX | LOCK_NB)) == 0 && ftruncate(fdw, 0) == 0) + { + std::FILE* file = fdopen(fdw, "w"); + if (file) return {file, std::move(name)}; + } + close(fdw); } - return {file, tools::close_file{}}; } #endif - return nullptr; + return {}; + } + + private_file::~private_file() noexcept + { + try + { + boost::system::error_code ec{}; + boost::filesystem::remove(filename(), ec); + } + catch (...) {} } #ifdef WIN32 diff --git a/src/common/util.h b/src/common/util.h index 2452bc9d5..48bdbbc28 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -60,8 +60,30 @@ namespace tools } }; - //! \return File only readable by owner. nullptr if `filename` exists. - std::unique_ptr<std::FILE, close_file> create_private_file(const std::string& filename); + //! A file restricted to process owner AND process. Deletes file on destruction. + class private_file { + std::unique_ptr<std::FILE, close_file> m_handle; + std::string m_filename; + + private_file(std::FILE* handle, std::string&& filename) noexcept; + public: + + //! `handle() == nullptr && filename.empty()`. + private_file() noexcept; + + /*! \return File only readable by owner and only used by this process + OR `private_file{}` on error. */ + static private_file create(std::string filename); + + private_file(private_file&&) = default; + private_file& operator=(private_file&&) = default; + + //! Deletes `filename()` and closes `handle()`. + ~private_file() noexcept; + + std::FILE* handle() const noexcept { return m_handle.get(); } + const std::string& filename() const noexcept { return m_filename; } + }; /*! \brief Returns the default data directory. * 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 745dfb72e..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 { @@ -869,4 +869,21 @@ namespace cryptonote block_hashes_calculated = block_hashes_calculated_count; block_hashes_cached = block_hashes_cached_count; } + //--------------------------------------------------------------- + crypto::secret_key encrypt_key(const crypto::secret_key &key, const std::string &passphrase) + { + crypto::hash hash; + crypto::cn_slow_hash(passphrase.data(), passphrase.size(), hash); + sc_add((unsigned char*)key.data, (const unsigned char*)key.data, (const unsigned char*)hash.data); + return key; + } + //--------------------------------------------------------------- + crypto::secret_key decrypt_key(const crypto::secret_key &key, const std::string &passphrase) + { + crypto::hash hash; + crypto::cn_slow_hash(passphrase.data(), passphrase.size(), hash); + sc_sub((unsigned char*)key.data, (const unsigned char*)key.data, (const unsigned char*)hash.data); + return key; + } + } diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h index d8ccf8eec..00080fb98 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.h +++ b/src/cryptonote_basic/cryptonote_format_utils.h @@ -212,6 +212,8 @@ namespace cryptonote bool is_valid_decomposed_amount(uint64_t amount); void get_hash_stats(uint64_t &tx_hashes_calculated, uint64_t &tx_hashes_cached, uint64_t &block_hashes_calculated, uint64_t & block_hashes_cached); + crypto::secret_key encrypt_key(const crypto::secret_key &key, const std::string &passphrase); + crypto::secret_key decrypt_key(const crypto::secret_key &key, const std::string &passphrase); #define CHECKED_GET_SPECIFIC_VARIANT(variant_var, specific_type, variable_name, fail_return_val) \ CHECK_AND_ASSERT_MES(variant_var.type() == typeid(specific_type), fail_return_val, "wrong variant type: " << variant_var.type().name() << ", expected " << typeid(specific_type).name()); \ specific_type& variable_name = boost::get<specific_type>(variant_var); diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index 3c5811d61..b620e3426 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -858,19 +858,6 @@ namespace cryptonote const boost::filesystem::path& power_supply_path = iter->path(); if (boost::filesystem::is_directory(power_supply_path)) { - std::ifstream power_supply_present_stream((power_supply_path / "present").string()); - if (power_supply_present_stream.fail()) - { - LOG_PRINT_L0("Unable to read from " << power_supply_path << " to check if power supply present"); - continue; - } - - if (power_supply_present_stream.get() != '1') - { - LOG_PRINT_L4("Power supply not present at " << power_supply_path); - continue; - } - boost::filesystem::path power_supply_type_path = power_supply_path / "type"; if (boost::filesystem::is_regular_file(power_supply_type_path)) { diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index cdb46dda9..a143c307f 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -91,7 +91,6 @@ #define BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT 10000 //by default, blocks ids count in synchronizing #define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT_PRE_V4 100 //by default, blocks count in blocks downloading #define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT 20 //by default, blocks count in blocks downloading -#define CRYPTONOTE_PROTOCOL_HOP_RELAX_COUNT 3 //value of hop, after which we use only announce of new block #define CRYPTONOTE_MEMPOOL_TX_LIVETIME 86400 //seconds, one day #define CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME 604800 //seconds, one week diff --git a/src/cryptonote_core/CMakeLists.txt b/src/cryptonote_core/CMakeLists.txt index 7c43323d4..169a38f0a 100644 --- a/src/cryptonote_core/CMakeLists.txt +++ b/src/cryptonote_core/CMakeLists.txt @@ -48,13 +48,14 @@ 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} ${cryptonote_core_private_headers}) target_link_libraries(cryptonote_core PUBLIC + version common cncrypto blockchain_db diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 619dbdc07..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" @@ -2384,6 +2383,26 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context } } + // from v7, sorted outs + if (m_hardfork->get_current_version() >= 7) { + const crypto::public_key *last_key = NULL; + for (size_t n = 0; n < tx.vout.size(); ++n) + { + const tx_out &o = tx.vout[n]; + if (o.target.type() == typeid(txout_to_key)) + { + const txout_to_key& out_to_key = boost::get<txout_to_key>(o.target); + if (last_key && memcmp(&out_to_key.key, last_key, sizeof(*last_key)) >= 0) + { + MERROR_VER("transaction has unsorted outputs"); + tvc.m_invalid_output = true; + return false; + } + last_key = &out_to_key.key; + } + } + } + return true; } //------------------------------------------------------------------ @@ -2552,6 +2571,25 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, } } + // from v7, sorted ins + if (hf_version >= 7) { + const crypto::key_image *last_key_image = NULL; + for (size_t n = 0; n < tx.vin.size(); ++n) + { + const txin_v &txin = tx.vin[n]; + if (txin.type() == typeid(txin_to_key)) + { + const txin_to_key& in_to_key = boost::get<txin_to_key>(txin); + if (last_key_image && memcmp(&in_to_key.k_image, last_key_image, sizeof(*last_key_image)) >= 0) + { + MERROR_VER("transaction has unsorted inputs"); + tvc.m_verifivation_failed = true; + return false; + } + last_key_image = &in_to_key.k_image; + } + } + } auto it = m_check_txin_table.find(tx_prefix_hash); if(it == m_check_txin_table.end()) { @@ -3276,7 +3314,7 @@ leave: // XXX old code adds miner tx here - int tx_index = 0; + size_t tx_index = 0; // Iterate over the block's transaction hashes, grabbing each // from the tx_pool and validating them. Each is then added // to txs. Keys spent in each are added to <keys> by the double spend check. @@ -3358,7 +3396,7 @@ leave: { // ND: if fast_check is enabled for blocks, there is no need to check // the transaction inputs, but do some sanity checks anyway. - if (memcmp(&m_blocks_txs_check[tx_index++], &tx_id, sizeof(tx_id)) != 0) + if (tx_index >= m_blocks_txs_check.size() || memcmp(&m_blocks_txs_check[tx_index++], &tx_id, sizeof(tx_id)) != 0) { MERROR_VER("Block with id: " << id << " has at least one transaction (id: " << tx_id << ") with wrong inputs."); //TODO: why is this done? make sure that keeping invalid blocks makes sense. @@ -3693,6 +3731,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list<block_complete_e MTRACE("Blockchain::" << __func__); TIME_MEASURE_START(prepare); bool stop_batch; + uint64_t bytes = 0; // Order of locking must be: // m_incoming_tx_lock (optional) @@ -3714,7 +3753,15 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list<block_complete_e if(blocks_entry.size() == 0) return false; - while (!(stop_batch = m_db->batch_start(blocks_entry.size()))) { + for (const auto &entry : blocks_entry) + { + bytes += entry.block.size(); + for (const auto &tx_blob : entry.txs) + { + bytes += tx_blob.size(); + } + } + while (!(stop_batch = m_db->batch_start(blocks_entry.size(), bytes))) { m_blockchain_lock.unlock(); m_tx_pool.unlock(); epee::misc_utils::sleep_no_w(1000); 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 56485aedf..57347fdbc 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"); } @@ -211,10 +211,9 @@ namespace cryptonote return m_blockchain_storage.get_current_blockchain_height(); } //----------------------------------------------------------------------------------------------- - bool core::get_blockchain_top(uint64_t& height, crypto::hash& top_id) const + void core::get_blockchain_top(uint64_t& height, crypto::hash& top_id) const { top_id = m_blockchain_storage.get_tail_id(height); - return true; } //----------------------------------------------------------------------------------------------- bool core::get_blocks(uint64_t start_offset, size_t count, std::list<std::pair<cryptonote::blobdata,block>>& blocks, std::list<cryptonote::blobdata>& txs) const @@ -1041,7 +1040,6 @@ namespace cryptonote { cryptonote_connection_context exclude_context = boost::value_initialized<cryptonote_connection_context>(); NOTIFY_NEW_BLOCK::request arg = AUTO_VAL_INIT(arg); - arg.hop = 0; arg.current_blockchain_height = m_blockchain_storage.get_current_blockchain_height(); std::list<crypto::hash> missed_txs; std::list<cryptonote::blobdata> txs; diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index 4ea33dbe1..1aed86b25 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -299,10 +299,8 @@ namespace cryptonote * * @param height return-by-reference height of the block * @param top_id return-by-reference hash of the block - * - * @return true */ - bool get_blockchain_top(uint64_t& height, crypto::hash& top_id) const; + void get_blockchain_top(uint64_t& height, crypto::hash& top_id) const; /** * @copydoc Blockchain::get_blocks(uint64_t, size_t, std::list<std::pair<cryptonote::blobdata,block>>&, std::list<transaction>&) const diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index 94f069827..19ed57aba 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -31,6 +31,7 @@ #include "include_base_utils.h" using namespace epee; +#include "common/apply_permutation.h" #include "cryptonote_tx_utils.h" #include "cryptonote_config.h" #include "cryptonote_basic/miner.h" @@ -156,7 +157,7 @@ namespace cryptonote return destinations[0].addr.m_view_public_key; } //--------------------------------------------------------------- - bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, bool rct) + bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, std::vector<tx_source_entry> sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, bool rct) { std::vector<rct::key> amount_keys; tx.set_null(); @@ -263,14 +264,25 @@ namespace cryptonote tx.vin.push_back(input_to_key); } - // "Shuffle" outs - std::vector<tx_destination_entry> shuffled_dsts(destinations); - std::random_shuffle(shuffled_dsts.begin(), shuffled_dsts.end(), [](unsigned int i) { return crypto::rand<unsigned int>() % i; }); + // sort ins by their key image + std::vector<size_t> ins_order(sources.size()); + for (size_t n = 0; n < sources.size(); ++n) + ins_order[n] = n; + std::sort(ins_order.begin(), ins_order.end(), [&](const size_t i0, const size_t i1) { + const txin_to_key &tk0 = boost::get<txin_to_key>(tx.vin[i0]); + const txin_to_key &tk1 = boost::get<txin_to_key>(tx.vin[i1]); + return memcmp(&tk0.k_image, &tk1.k_image, sizeof(tk0.k_image)) < 0; + }); + tools::apply_permutation(ins_order, [&] (size_t i0, size_t i1) { + std::swap(tx.vin[i0], tx.vin[i1]); + std::swap(in_contexts[i0], in_contexts[i1]); + std::swap(sources[i0], sources[i1]); + }); uint64_t summary_outs_money = 0; //fill outputs size_t output_index = 0; - for(const tx_destination_entry& dst_entr: shuffled_dsts) + for(const tx_destination_entry& dst_entr: destinations) { CHECK_AND_ASSERT_MES(dst_entr.amount > 0 || tx.version > 1, false, "Destination with wrong amount: " << dst_entr.amount); crypto::key_derivation derivation; @@ -297,6 +309,23 @@ 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) + outs_order[n] = n; + std::sort(outs_order.begin(), outs_order.end(), [&](size_t i0, size_t i1) { + const txout_to_key &tk0 = boost::get<txout_to_key>(tx.vout[i0].target); + const txout_to_key &tk1 = boost::get<txout_to_key>(tx.vout[i1].target); + return memcmp(&tk0.key, &tk1.key, sizeof(tk0.key)) < 0; + }); + tools::apply_permutation(outs_order, [&] (size_t i0, size_t i1) { + std::swap(tx.vout[i0], tx.vout[i1]); + if (!amount_keys.empty()) + std::swap(amount_keys[i0], amount_keys[i1]); + }); +#endif + //check money if(summary_outs_money > summary_inputs_money ) { @@ -484,8 +513,9 @@ namespace cryptonote std::string genesis_coinbase_tx_hex = config::GENESIS_TX; blobdata tx_bl; - string_tools::parse_hexstr_to_binbuff(genesis_coinbase_tx_hex, tx_bl); - bool r = parse_and_validate_tx_from_blob(tx_bl, bl.miner_tx); + bool r = string_tools::parse_hexstr_to_binbuff(genesis_coinbase_tx_hex, tx_bl); + CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob"); + r = parse_and_validate_tx_from_blob(tx_bl, bl.miner_tx); CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob"); bl.major_version = CURRENT_BLOCK_MAJOR_VERSION; bl.minor_version = CURRENT_BLOCK_MINOR_VERSION; diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h index 7aa7c280d..69254fb5f 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.h +++ b/src/cryptonote_core/cryptonote_tx_utils.h @@ -71,7 +71,7 @@ namespace cryptonote //--------------------------------------------------------------- crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const account_keys &sender_keys); bool construct_tx(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time); - bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, bool rct = false); + bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, std::vector<tx_source_entry> sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, bool rct = false); bool generate_genesis_block( block& bl diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 7de392036..9071c330c 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -202,6 +202,9 @@ namespace cryptonote return false; } + // assume failure during verification steps until success is certain + tvc.m_verifivation_failed = true; + time_t receive_time = time(nullptr); crypto::hash max_used_block_id = null_hash; @@ -246,6 +249,7 @@ namespace cryptonote { LOG_PRINT_L1("tx used wrong inputs, rejected"); tvc.m_verifivation_failed = true; + tvc.m_invalid_input = true; return false; } }else @@ -285,9 +289,6 @@ namespace cryptonote tvc.m_should_be_relayed = true; } - // assume failure during verification steps until success is certain - tvc.m_verifivation_failed = true; - tvc.m_verifivation_failed = false; MINFO("Transaction added to pool: txid " << id << " bytes: " << blob_size << " fee/byte: " << (fee / (double)blob_size)); @@ -298,7 +299,8 @@ namespace cryptonote { crypto::hash h = null_hash; size_t blob_size = 0; - get_transaction_hash(tx, h, blob_size); + if (!get_transaction_hash(tx, h, blob_size) || blob_size == 0) + return false; return add_tx(tx, h, blob_size, tvc, keeped_by_block, relayed, do_not_relay, version); } //--------------------------------------------------------------------------------- @@ -1090,12 +1092,13 @@ namespace cryptonote m_txs_by_fee_and_receive_time.clear(); m_spent_key_images.clear(); - return m_blockchain.for_all_txpool_txes([this](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd) { + std::vector<crypto::hash> remove; + bool r = m_blockchain.for_all_txpool_txes([this, &remove](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd) { cryptonote::transaction tx; if (!parse_and_validate_tx_from_blob(*bd, tx)) { - MERROR("Failed to parse tx from txpool"); - return false; + MWARNING("Failed to parse tx from txpool, removing"); + remove.push_back(txid); } if (!insert_key_images(tx, meta.kept_by_block)) { @@ -1105,6 +1108,25 @@ namespace cryptonote m_txs_by_fee_and_receive_time.emplace(std::pair<double, time_t>(meta.fee / (double)meta.blob_size, meta.receive_time), txid); return true; }, true); + if (!r) + return false; + if (!remove.empty()) + { + LockedTXN lock(m_blockchain); + for (const auto &txid: remove) + { + try + { + m_blockchain.remove_txpool_tx(txid); + } + catch (const std::exception &e) + { + MWARNING("Failed to remove corrupt transaction: " << txid); + // ignore error + } + } + } + return true; } //--------------------------------------------------------------------------------- diff --git a/src/cryptonote_protocol/CMakeLists.txt b/src/cryptonote_protocol/CMakeLists.txt index 4ce380a48..347e48eee 100644 --- a/src/cryptonote_protocol/CMakeLists.txt +++ b/src/cryptonote_protocol/CMakeLists.txt @@ -39,5 +39,3 @@ target_link_libraries(cryptonote_protocol p2p PRIVATE ${EXTRA_LIBRARIES}) -add_dependencies(cryptonote_protocol - version) 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_defs.h b/src/cryptonote_protocol/cryptonote_protocol_defs.h index 71e205c23..1804cc101 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_defs.h +++ b/src/cryptonote_protocol/cryptonote_protocol_defs.h @@ -128,12 +128,10 @@ namespace cryptonote { block_complete_entry b; uint64_t current_blockchain_height; - uint32_t hop; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(b) KV_SERIALIZE(current_blockchain_height) - KV_SERIALIZE(hop) END_KV_SERIALIZE_MAP() }; }; @@ -254,12 +252,10 @@ namespace cryptonote { block_complete_entry b; uint64_t current_blockchain_height; - uint32_t hop; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(b) KV_SERIALIZE(current_blockchain_height) - KV_SERIALIZE(hop) END_KV_SERIALIZE_MAP() }; }; @@ -276,13 +272,11 @@ namespace cryptonote crypto::hash block_hash; uint64_t current_blockchain_height; std::vector<size_t> missing_tx_indices; - uint32_t hop; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE_VAL_POD_AS_BLOB(block_hash) KV_SERIALIZE(current_blockchain_height) KV_SERIALIZE_CONTAINER_POD_AS_BLOB(missing_tx_indices) - KV_SERIALIZE(hop) END_KV_SERIALIZE_MAP() }; }; diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index 803d948cc..58e5fc380 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -336,7 +336,7 @@ namespace cryptonote template<class t_core> int t_cryptonote_protocol_handler<t_core>::handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context) { - MLOG_P2P_MESSAGE("Received NOTIFY_NEW_BLOCK (hop " << arg.hop << ", " << arg.b.txs.size() << " txes)"); + MLOG_P2P_MESSAGE("Received NOTIFY_NEW_BLOCK (" << arg.b.txs.size() << " txes)"); if(context.m_state != cryptonote_connection_context::state_normal) return 1; if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks @@ -379,7 +379,6 @@ namespace cryptonote } if(bvc.m_added_to_main_chain) { - ++arg.hop; //TODO: Add here announce protocol usage relay_block(arg, context); }else if(bvc.m_marked_as_orphaned) @@ -397,7 +396,7 @@ namespace cryptonote template<class t_core> int t_cryptonote_protocol_handler<t_core>::handle_notify_new_fluffy_block(int command, NOTIFY_NEW_FLUFFY_BLOCK::request& arg, cryptonote_connection_context& context) { - MLOG_P2P_MESSAGE("Received NOTIFY_NEW_FLUFFY_BLOCK (height " << arg.current_blockchain_height << ", hop " << arg.hop << ", " << arg.b.txs.size() << " txes)"); + MLOG_P2P_MESSAGE("Received NOTIFY_NEW_FLUFFY_BLOCK (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)"); if(context.m_state != cryptonote_connection_context::state_normal) return 1; if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks @@ -607,7 +606,6 @@ namespace cryptonote MDEBUG(" tx " << new_block.tx_hashes[txidx]); NOTIFY_REQUEST_FLUFFY_MISSING_TX::request missing_tx_req; missing_tx_req.block_hash = get_block_hash(new_block); - missing_tx_req.hop = arg.hop; missing_tx_req.current_blockchain_height = arg.current_blockchain_height; missing_tx_req.missing_tx_indices = std::move(need_tx_indices); @@ -644,10 +642,8 @@ namespace cryptonote } if( bvc.m_added_to_main_chain ) { - ++arg.hop; //TODO: Add here announce protocol usage NOTIFY_NEW_BLOCK::request reg_arg = AUTO_VAL_INIT(reg_arg); - reg_arg.hop = arg.hop; reg_arg.current_blockchain_height = arg.current_blockchain_height; reg_arg.b = b; relay_block(reg_arg, context); @@ -700,7 +696,6 @@ namespace cryptonote NOTIFY_NEW_FLUFFY_BLOCK::request fluffy_response; fluffy_response.b.block = t_serializable_object_to_blob(b); fluffy_response.current_blockchain_height = arg.current_blockchain_height; - fluffy_response.hop = arg.hop; for(auto& tx_idx: arg.missing_tx_indices) { if(tx_idx < b.tx_hashes.size()) @@ -936,7 +931,8 @@ namespace cryptonote } // get the last parsed block, which should be the highest one - if(m_core.have_block(cryptonote::get_block_hash(b))) + const crypto::hash last_block_hash = cryptonote::get_block_hash(b); + if(m_core.have_block(last_block_hash)) { const uint64_t subchain_height = start_height + arg.blocks.size(); LOG_DEBUG_CC(context, "These are old blocks, ignoring: blocks " << start_height << " - " << (subchain_height-1) << ", blockchain height " << m_core.get_current_blockchain_height()); @@ -954,7 +950,7 @@ namespace cryptonote MDEBUG(context << " adding span: " << arg.blocks.size() << " at height " << start_height << ", " << dt.total_microseconds()/1e6 << " seconds, " << (rate/1e3) << " kB/s, size now " << (m_block_queue.get_data_size() + blocks_size) / 1048576.f << " MB"); m_block_queue.add_blocks(start_height, arg.blocks, context.m_connection_id, rate, blocks_size); - context.m_last_known_hash = cryptonote::get_blob_hash(arg.blocks.back().block); + context.m_last_known_hash = last_block_hash; if (!m_core.get_test_drop_download() || !m_core.get_test_drop_download_height()) { // DISCARD BLOCKS for testing return 1; @@ -1488,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); } @@ -1605,7 +1601,6 @@ skip: bool t_cryptonote_protocol_handler<t_core>::relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context) { NOTIFY_NEW_FLUFFY_BLOCK::request fluffy_arg = AUTO_VAL_INIT(fluffy_arg); - fluffy_arg.hop = arg.hop; fluffy_arg.current_blockchain_height = arg.current_blockchain_height; std::list<blobdata> fluffy_txs; fluffy_arg.b = arg.b; diff --git a/src/daemon/CMakeLists.txt b/src/daemon/CMakeLists.txt index 782667867..d0fc1d846 100644 --- a/src/daemon/CMakeLists.txt +++ b/src/daemon/CMakeLists.txt @@ -94,6 +94,7 @@ target_link_libraries(daemon daemonizer serialization daemon_rpc_server + version ${Boost_CHRONO_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} @@ -102,7 +103,6 @@ target_link_libraries(daemon ${CMAKE_THREAD_LIBS_INIT} ${ZMQ_LIB} ${EXTRA_LIBRARIES}) -add_dependencies(daemon version) set_property(TARGET daemon PROPERTY OUTPUT_NAME "monerod") diff --git a/src/daemon/command_line_args.h b/src/daemon/command_line_args.h index f19d5cc63..7fa58f9d8 100644 --- a/src/daemon/command_line_args.h +++ b/src/daemon/command_line_args.h @@ -46,6 +46,11 @@ namespace daemon_args , "Specify log file" , "" }; + const command_line::arg_descriptor<std::size_t> arg_max_log_file_size = { + "max-log-file-size" + , "Specify maximum log file size [B]" + , MAX_LOG_FILE_SIZE + }; const command_line::arg_descriptor<std::string> arg_log_level = { "log-level" , "" diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp index d949a57b1..395157869 100644 --- a/src/daemon/command_parser_executor.cpp +++ b/src/daemon/command_parser_executor.cpp @@ -334,17 +334,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 +354,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 +374,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 9df698547..b9f503c6b 100644 --- a/src/daemon/command_server.cpp +++ b/src/daemon/command_server.cpp @@ -241,7 +241,7 @@ t_command_server::t_command_server( m_command_lookup.set_handler( "bc_dyn_stats" , std::bind(&t_command_parser_executor::print_blockchain_dynamic_stats, &m_parser, p::_1) - , "Print information about current blockchain dynamic state" + , "Print information about current blockchain dynamic state, bc_dyn_stats <last n blocks>" ); m_command_lookup.set_handler( "update" diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp index 8f6d542b6..acc23b9f9 100644 --- a/src/daemon/main.cpp +++ b/src/daemon/main.cpp @@ -88,6 +88,7 @@ int main(int argc, char const * argv[]) bf::path default_log = default_data_dir / std::string(CRYPTONOTE_NAME ".log"); command_line::add_arg(core_settings, daemon_args::arg_log_file, default_log.string()); command_line::add_arg(core_settings, daemon_args::arg_log_level); + command_line::add_arg(core_settings, daemon_args::arg_max_log_file_size); command_line::add_arg(core_settings, daemon_args::arg_max_concurrency); command_line::add_arg(core_settings, daemon_args::arg_zmq_rpc_bind_ip); command_line::add_arg(core_settings, daemon_args::arg_zmq_rpc_bind_port); @@ -207,7 +208,7 @@ int main(int argc, char const * argv[]) if (! vm["log-file"].defaulted()) log_file_path = command_line::get_arg(vm, daemon_args::arg_log_file); log_file_path = bf::absolute(log_file_path, relative_path_base); - mlog_configure(log_file_path.string(), true); + mlog_configure(log_file_path.string(), true, command_line::get_arg(vm, daemon_args::arg_max_log_file_size)); // Set log level if (!vm["log-level"].defaulted()) diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index cda6f3f95..3cd32ec2f 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -700,6 +700,7 @@ bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash) { std::string fail_message = "Problem fetching transaction"; req.txs_hashes.push_back(epee::string_tools::pod_to_hex(transaction_hash)); + req.decode_as_json = false; if (m_is_rpc) { if (!m_rpc_client->rpc_request(req, res, "/gettransactions", fail_message.c_str())) @@ -782,7 +783,7 @@ bool t_rpc_command_executor::is_key_image_spent(const crypto::key_image &ki) { if (1 == res.spent_status.size()) { // first as hex - tools::success_msg_writer() << ki << ": " << (res.spent_status.front() ? "spent" : "unspent"); + tools::success_msg_writer() << ki << ": " << (res.spent_status.front() ? "spent" : "unspent") << (res.spent_status.front() == cryptonote::COMMAND_RPC_IS_KEY_IMAGE_SPENT::SPENT_IN_POOL ? " (in pool)" : ""); } else { @@ -1129,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/debug_utilities/CMakeLists.txt b/src/debug_utilities/CMakeLists.txt index 99198dc57..7a82c12d9 100644 --- a/src/debug_utilities/CMakeLists.txt +++ b/src/debug_utilities/CMakeLists.txt @@ -42,8 +42,6 @@ target_link_libraries(cn_deserialize epee ${CMAKE_THREAD_LIBS_INIT}) -add_dependencies(cn_deserialize - version) set_property(TARGET cn_deserialize PROPERTY OUTPUT_NAME "monero-utils-deserialize") @@ -65,8 +63,6 @@ target_link_libraries(object_sizes epee ${CMAKE_THREAD_LIBS_INIT}) -add_dependencies(object_sizes - version) set_property(TARGET object_sizes PROPERTY OUTPUT_NAME "monero-utils-object-sizes") diff --git a/src/p2p/CMakeLists.txt b/src/p2p/CMakeLists.txt index 0704940b5..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} @@ -47,5 +48,3 @@ target_link_libraries(p2p ${Boost_THREAD_LIBRARY} PRIVATE ${EXTRA_LIBRARIES}) -add_dependencies(p2p - version) diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 22ae5ec26..8bbaa9138 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -105,7 +105,7 @@ namespace nodetool bool init(const boost::program_options::variables_map& vm); bool deinit(); bool send_stop_signal(); - uint32_t get_this_peer_port(){return m_listenning_port;} + uint32_t get_this_peer_port(){return m_listening_port;} t_payload_net_handler& get_payload_object(); template <class Archive, class t_version_type> @@ -218,6 +218,8 @@ namespace nodetool bool is_peer_used(const peerlist_entry& peer); bool is_peer_used(const anchor_peerlist_entry& peer); bool is_addr_connected(const epee::net_utils::network_address& peer); + void add_upnp_port_mapping(uint32_t port); + void delete_upnp_port_mapping(uint32_t port); template<class t_callback> bool try_ping(basic_node_data& node_data, p2p_connection_context& context, t_callback cb); bool try_get_support_flags(const p2p_connection_context& context, std::function<void(p2p_connection_context&, const uint32_t&)> f); @@ -287,7 +289,7 @@ namespace nodetool bool m_have_address; bool m_first_connection_maker_call; - uint32_t m_listenning_port; + uint32_t m_listening_port; uint32_t m_external_port; uint32_t m_ip_address; bool m_allow_local_ip; diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 889cfaf9d..f1ca50f76 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -573,55 +573,15 @@ namespace nodetool res = m_net_server.init_server(m_port, m_bind_ip); CHECK_AND_ASSERT_MES(res, false, "Failed to bind server"); - m_listenning_port = m_net_server.get_binded_port(); - MLOG_GREEN(el::Level::Info, "Net service bound to " << m_bind_ip << ":" << m_listenning_port); + m_listening_port = m_net_server.get_binded_port(); + MLOG_GREEN(el::Level::Info, "Net service bound to " << m_bind_ip << ":" << m_listening_port); if(m_external_port) MDEBUG("External port defined as " << m_external_port); - // Add UPnP port mapping - if(m_no_igd == false) { - MDEBUG("Attempting to add IGD port mapping."); - int result; -#if MINIUPNPC_API_VERSION > 13 - // default according to miniupnpc.h - unsigned char ttl = 2; - UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, 0, ttl, &result); -#else - UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, 0, &result); -#endif - UPNPUrls urls; - IGDdatas igdData; - char lanAddress[64]; - result = UPNP_GetValidIGD(deviceList, &urls, &igdData, lanAddress, sizeof lanAddress); - freeUPNPDevlist(deviceList); - if (result != 0) { - if (result == 1) { - std::ostringstream portString; - portString << m_listenning_port; - - // Delete the port mapping before we create it, just in case we have dangling port mapping from the daemon not being shut down correctly - UPNP_DeletePortMapping(urls.controlURL, igdData.first.servicetype, portString.str().c_str(), "TCP", 0); - - int portMappingResult; - portMappingResult = UPNP_AddPortMapping(urls.controlURL, igdData.first.servicetype, portString.str().c_str(), portString.str().c_str(), lanAddress, CRYPTONOTE_NAME, "TCP", 0, "0"); - if (portMappingResult != 0) { - LOG_ERROR("UPNP_AddPortMapping failed, error: " << strupnperror(portMappingResult)); - } else { - MLOG_GREEN(el::Level::Info, "Added IGD port mapping."); - } - } else if (result == 2) { - MWARNING("IGD was found but reported as not connected."); - } else if (result == 3) { - MWARNING("UPnP device was found but not recognized as IGD."); - } else { - MWARNING("UPNP_GetValidIGD returned an unknown result code."); - } + // add UPnP port mapping + if(!m_no_igd) + add_upnp_port_mapping(m_listening_port); - FreeUPNPUrls(&urls); - } else { - MINFO("No IGD was found."); - } - } return res; } //----------------------------------------------------------------------------------- @@ -688,6 +648,9 @@ namespace nodetool kill(); m_peerlist.deinit(); m_net_server.deinit_server(); + // remove UPnP port mapping + if(!m_no_igd) + delete_upnp_port_mapping(m_listening_port); return store_config(); } //----------------------------------------------------------------------------------- @@ -1127,6 +1090,8 @@ namespace nodetool if (use_white_list) { local_peers_count = m_peerlist.get_white_peers_count(); + if (!local_peers_count) + return false; max_random_index = std::min<uint64_t>(local_peers_count -1, 20); random_index = get_random_index_with_fixed_probability(max_random_index); } else { @@ -1389,7 +1354,7 @@ namespace nodetool node_data.local_time = local_time; node_data.peer_id = m_config.m_peer_id; if(!m_hide_my_port) - node_data.my_port = m_external_port ? m_external_port : m_listenning_port; + node_data.my_port = m_external_port ? m_external_port : m_listening_port; else node_data.my_port = 0; node_data.network_id = m_network_id; @@ -1951,8 +1916,13 @@ namespace nodetool template<class t_payload_net_handler> bool node_server<t_payload_net_handler>::gray_peerlist_housekeeping() { + if (!m_exclusive_peers.empty()) return true; + peerlist_entry pe = AUTO_VAL_INIT(pe); + if (m_net_server.is_stop_signal_sent()) + return false; + if (!m_peerlist.get_random_gray_peer(pe)) { return false; } @@ -1973,4 +1943,93 @@ namespace nodetool return true; } + + template<class t_payload_net_handler> + void node_server<t_payload_net_handler>::add_upnp_port_mapping(uint32_t port) + { + MDEBUG("Attempting to add IGD port mapping."); + int result; +#if MINIUPNPC_API_VERSION > 13 + // default according to miniupnpc.h + unsigned char ttl = 2; + UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, 0, ttl, &result); +#else + UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, 0, &result); +#endif + UPNPUrls urls; + IGDdatas igdData; + char lanAddress[64]; + result = UPNP_GetValidIGD(deviceList, &urls, &igdData, lanAddress, sizeof lanAddress); + freeUPNPDevlist(deviceList); + if (result != 0) { + if (result == 1) { + std::ostringstream portString; + portString << port; + + // Delete the port mapping before we create it, just in case we have dangling port mapping from the daemon not being shut down correctly + UPNP_DeletePortMapping(urls.controlURL, igdData.first.servicetype, portString.str().c_str(), "TCP", 0); + + int portMappingResult; + portMappingResult = UPNP_AddPortMapping(urls.controlURL, igdData.first.servicetype, portString.str().c_str(), portString.str().c_str(), lanAddress, CRYPTONOTE_NAME, "TCP", 0, "0"); + if (portMappingResult != 0) { + LOG_ERROR("UPNP_AddPortMapping failed, error: " << strupnperror(portMappingResult)); + } else { + MLOG_GREEN(el::Level::Info, "Added IGD port mapping."); + } + } else if (result == 2) { + MWARNING("IGD was found but reported as not connected."); + } else if (result == 3) { + MWARNING("UPnP device was found but not recognized as IGD."); + } else { + MWARNING("UPNP_GetValidIGD returned an unknown result code."); + } + + FreeUPNPUrls(&urls); + } else { + MINFO("No IGD was found."); + } + } + + template<class t_payload_net_handler> + void node_server<t_payload_net_handler>::delete_upnp_port_mapping(uint32_t port) + { + MDEBUG("Attempting to delete IGD port mapping."); + int result; +#if MINIUPNPC_API_VERSION > 13 + // default according to miniupnpc.h + unsigned char ttl = 2; + UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, 0, ttl, &result); +#else + UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, 0, &result); +#endif + UPNPUrls urls; + IGDdatas igdData; + char lanAddress[64]; + result = UPNP_GetValidIGD(deviceList, &urls, &igdData, lanAddress, sizeof lanAddress); + freeUPNPDevlist(deviceList); + if (result != 0) { + if (result == 1) { + std::ostringstream portString; + portString << port; + + int portMappingResult; + portMappingResult = UPNP_DeletePortMapping(urls.controlURL, igdData.first.servicetype, portString.str().c_str(), "TCP", 0); + if (portMappingResult != 0) { + LOG_ERROR("UPNP_DeletePortMapping failed, error: " << strupnperror(portMappingResult)); + } else { + MLOG_GREEN(el::Level::Info, "Deleted IGD port mapping."); + } + } else if (result == 2) { + MWARNING("IGD was found but reported as not connected."); + } else if (result == 3) { + MWARNING("UPnP device was found but not recognized as IGD."); + } else { + MWARNING("UPNP_GetValidIGD returned an unknown result code."); + } + + FreeUPNPUrls(&urls); + } else { + MINFO("No IGD was found."); + } + } } diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h index a30a05422..8372445aa 100644 --- a/src/p2p/net_peerlist.h +++ b/src/p2p/net_peerlist.h @@ -190,35 +190,16 @@ namespace nodetool if (ver < 6) return; - if(ver < 3) - return; CRITICAL_REGION_LOCAL(m_peerlist_lock); - if(ver < 4) - { - //loading data from old storage - peers_indexed_old pio; - a & pio; - peers_indexed_from_old(pio, m_peers_white); - return; - } #if 0 // trouble loading more than one peer, can't find why a & m_peers_white; a & m_peers_gray; + a & m_peers_anchor; #else serialize_peers(a, m_peers_white, peerlist_entry(), ver); serialize_peers(a, m_peers_gray, peerlist_entry(), ver); -#endif - - if(ver < 5) { - return; - } - -#if 0 - // trouble loading more than one peer, can't find why - a & m_peers_anchor; -#else serialize_peers(a, m_peers_anchor, anchor_peerlist_entry(), ver); #endif } diff --git a/src/rpc/CMakeLists.txt b/src/rpc/CMakeLists.txt index b5c38b1a8..23bb6aaae 100644 --- a/src/rpc/CMakeLists.txt +++ b/src/rpc/CMakeLists.txt @@ -117,10 +117,3 @@ target_link_libraries(daemon_rpc_server ${EXTRA_LIBRARIES}) target_include_directories(daemon_rpc_server PUBLIC ${ZMQ_INCLUDE_PATH}) target_include_directories(obj_daemon_rpc_server PUBLIC ${ZMQ_INCLUDE_PATH}) - - -add_dependencies(rpc - version) - -add_dependencies(daemon_rpc_server - version) diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 1f7f4a1ff..9730cdf46 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -50,6 +50,16 @@ using namespace epee; #define MAX_RESTRICTED_FAKE_OUTS_COUNT 40 #define MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT 500 +namespace +{ + void add_reason(std::string &reasons, const char *reason) + { + if (!reasons.empty()) + reasons += ", "; + reasons += reason; + } +} + namespace cryptonote { @@ -128,11 +138,7 @@ namespace cryptonote { CHECK_CORE_BUSY(); crypto::hash top_hash; - if (!m_core.get_blockchain_top(res.height, top_hash)) - { - res.status = "Failed"; - return false; - } + m_core.get_blockchain_top(res.height, top_hash); ++res.height; // turn top block height into blockchain height res.top_block_hash = string_tools::pod_to_hex(top_hash); res.target_height = m_core.get_target_blockchain_height(); @@ -478,18 +484,30 @@ namespace cryptonote bool r = m_core.get_pool_transactions(pool_txs); if(r) { - for (std::list<transaction>::const_iterator i = pool_txs.begin(); i != pool_txs.end(); ++i) + // sort to match original request + std::list<transaction> sorted_txs; + std::list<cryptonote::transaction>::const_iterator i; + for (const crypto::hash &h: vh) { - crypto::hash tx_hash = get_transaction_hash(*i); - std::list<crypto::hash>::iterator mi = std::find(missed_txs.begin(), missed_txs.end(), tx_hash); - if (mi != missed_txs.end()) + if (std::find(missed_txs.begin(), missed_txs.end(), h) == missed_txs.end()) { - pool_tx_hashes.insert(tx_hash); - missed_txs.erase(mi); - txs.push_back(*i); + // core returns the ones it finds in the right order + if (get_transaction_hash(txs.front()) != h) + { + res.status = "Failed: tx hash mismatch"; + return true; + } + sorted_txs.push_back(std::move(txs.front())); + txs.pop_front(); + } + else if ((i = std::find_if(pool_txs.begin(), pool_txs.end(), [h](cryptonote::transaction &tx) { return h == cryptonote::get_transaction_hash(tx); })) != pool_txs.end()) + { + sorted_txs.push_back(*i); + missed_txs.remove(h); ++found_in_pool; } } + txs = sorted_txs; } LOG_PRINT_L2("Found " << found_in_pool << "/" << vh.size() << " transactions in the pool"); } @@ -510,11 +528,12 @@ namespace cryptonote e.in_pool = pool_tx_hashes.find(tx_hash) != pool_tx_hashes.end(); if (e.in_pool) { - e.block_height = std::numeric_limits<uint64_t>::max(); + e.block_height = e.block_timestamp = std::numeric_limits<uint64_t>::max(); } else { e.block_height = m_core.get_blockchain_storage().get_db().get_tx_block_height(tx_hash); + e.block_timestamp = m_core.get_blockchain_storage().get_db().get_block_timestamp(e.block_height); } // fill up old style responses too, in case an old wallet asks @@ -623,31 +642,33 @@ namespace cryptonote tx_verification_context tvc = AUTO_VAL_INIT(tvc); if(!m_core.handle_incoming_tx(tx_blob, tvc, false, false, req.do_not_relay) || tvc.m_verifivation_failed) { - if (tvc.m_verifivation_failed) - { - LOG_PRINT_L0("[on_send_raw_tx]: tx verification failed"); - } - else - { - LOG_PRINT_L0("[on_send_raw_tx]: Failed to process tx"); - } res.status = "Failed"; + res.reason = ""; if ((res.low_mixin = tvc.m_low_mixin)) - res.reason = "ring size too small"; + add_reason(res.reason, "ring size too small"); if ((res.double_spend = tvc.m_double_spend)) - res.reason = "double spend"; + add_reason(res.reason, "double spend"); if ((res.invalid_input = tvc.m_invalid_input)) - res.reason = "invalid input"; + add_reason(res.reason, "invalid input"); if ((res.invalid_output = tvc.m_invalid_output)) - res.reason = "invalid output"; + add_reason(res.reason, "invalid output"); if ((res.too_big = tvc.m_too_big)) - res.reason = "too big"; + add_reason(res.reason, "too big"); if ((res.overspend = tvc.m_overspend)) - res.reason = "overspend"; + add_reason(res.reason, "overspend"); if ((res.fee_too_low = tvc.m_fee_too_low)) - res.reason = "fee too low"; + add_reason(res.reason, "fee too low"); if ((res.not_rct = tvc.m_not_rct)) - res.reason = "tx is not ringct"; + add_reason(res.reason, "tx is not ringct"); + const std::string punctuation = res.reason.empty() ? "" : ": "; + if (tvc.m_verifivation_failed) + { + LOG_PRINT_L0("[on_send_raw_tx]: tx verification failed" << punctuation << res.reason); + } + else + { + LOG_PRINT_L0("[on_send_raw_tx]: Failed to process tx" << punctuation << res.reason); + } return true; } @@ -948,7 +969,7 @@ namespace cryptonote LOG_ERROR("Failed to find tx pub key in blockblob"); return false; } - res.reserved_offset += sizeof(tx_pub_key) + 3; //3 bytes: tag for TX_EXTRA_TAG_PUBKEY(1 byte), tag for TX_EXTRA_NONCE(1 byte), counter in TX_EXTRA_NONCE(1 byte) + res.reserved_offset += sizeof(tx_pub_key) + 2; //2 bytes: tag for TX_EXTRA_NONCE(1 byte), counter in TX_EXTRA_NONCE(1 byte) if(res.reserved_offset + req.reserve_size > block_blob.size()) { error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; @@ -1048,13 +1069,7 @@ namespace cryptonote } uint64_t last_block_height; crypto::hash last_block_hash; - bool have_last_block_hash = m_core.get_blockchain_top(last_block_height, last_block_hash); - if (!have_last_block_hash) - { - error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; - error_resp.message = "Internal error: can't get last block hash."; - return false; - } + m_core.get_blockchain_top(last_block_height, last_block_hash); block last_block; bool have_last_block = m_core.get_block_by_hash(last_block_hash, last_block); if (!have_last_block) @@ -1287,11 +1302,7 @@ namespace cryptonote } crypto::hash top_hash; - if (!m_core.get_blockchain_top(res.height, top_hash)) - { - res.status = "Failed"; - return false; - } + m_core.get_blockchain_top(res.height, top_hash); ++res.height; // turn top block height into blockchain height res.top_block_hash = string_tools::pod_to_hex(top_hash); res.target_height = m_core.get_target_blockchain_height(); @@ -1522,6 +1533,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 @@ -1703,11 +1761,7 @@ namespace cryptonote } crypto::hash top_hash; - if (!m_core.get_blockchain_top(res.height, top_hash)) - { - res.status = "Failed"; - return false; - } + m_core.get_blockchain_top(res.height, top_hash); ++res.height; // turn top block height into blockchain height res.target_height = m_core.get_target_blockchain_height(); 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 88327dd75..ecf546bb0 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -49,7 +49,7 @@ namespace cryptonote // advance which version they will stop working with // Don't go over 32767 for any of these #define CORE_RPC_VERSION_MAJOR 1 -#define CORE_RPC_VERSION_MINOR 13 +#define CORE_RPC_VERSION_MINOR 14 #define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor)) #define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR) @@ -215,6 +215,7 @@ namespace cryptonote std::string as_json; bool in_pool; uint64_t block_height; + uint64_t block_timestamp; std::vector<uint64_t> output_indices; BEGIN_KV_SERIALIZE_MAP() @@ -223,6 +224,7 @@ namespace cryptonote KV_SERIALIZE(as_json) KV_SERIALIZE(in_pool) KV_SERIALIZE(block_height) + KV_SERIALIZE(block_timestamp) KV_SERIALIZE(output_indices) END_KV_SERIALIZE_MAP() }; @@ -1242,6 +1244,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 ead3fdd58..e35389f9c 100644 --- a/src/serialization/json_object.cpp +++ b/src/serialization/json_object.cpp @@ -29,6 +29,7 @@ #include "json_object.h" #include <limits> +#include <type_traits> #include "string_tools.h" namespace cryptonote @@ -52,8 +53,9 @@ namespace void convert_numeric(Source source, Type& i) { static_assert( + (std::is_same<Type, char>() && std::is_same<Source, int>()) || std::numeric_limits<Source>::is_signed == std::numeric_limits<Type>::is_signed, - "source and destination signs do not match" + "comparisons below may have undefined behavior" ); if (source < std::numeric_limits<Type>::min()) { 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/CMakeLists.txt b/src/simplewallet/CMakeLists.txt index 443e9b87e..b56085b8f 100644 --- a/src/simplewallet/CMakeLists.txt +++ b/src/simplewallet/CMakeLists.txt @@ -49,14 +49,13 @@ target_link_libraries(simplewallet common mnemonics p2p + version ${Boost_CHRONO_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_THREAD_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_LIBRARIES}) -add_dependencies(simplewallet - version) set_property(TARGET simplewallet PROPERTY OUTPUT_NAME "monero-wallet-cli") diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 857e2af6e..937403c66 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -290,7 +290,7 @@ bool simple_wallet::spendkey(const std::vector<std::string> &args/* = std::vecto return true; } -bool simple_wallet::seed(const std::vector<std::string> &args/* = std::vector<std::string>()*/) +bool simple_wallet::print_seed(bool encrypted) { bool success = false; std::string electrum_words; @@ -311,7 +311,16 @@ bool simple_wallet::seed(const std::vector<std::string> &args/* = std::vector<st m_wallet->set_seed_language(mnemonic_language); } - success = m_wallet->get_seed(electrum_words); + std::string seed_pass; + if (encrypted) + { + auto pwd_container = tools::password_container::prompt(true, tr("Enter optional seed encryption passphrase, empty to see raw seed")); + if (std::cin.eof() || !pwd_container) + return true; + seed_pass = pwd_container->password(); + } + + success = m_wallet->get_seed(electrum_words, seed_pass); } if (success) @@ -325,6 +334,16 @@ bool simple_wallet::seed(const std::vector<std::string> &args/* = std::vector<st return true; } +bool simple_wallet::seed(const std::vector<std::string> &args/* = std::vector<std::string>()*/) +{ + return print_seed(false); +} + +bool simple_wallet::encrypted_seed(const std::vector<std::string> &args/* = std::vector<std::string>()*/) +{ + return print_seed(true); +} + bool simple_wallet::seed_set_language(const std::vector<std::string> &args/* = std::vector<std::string>()*/) { if (m_wallet->watch_only()) @@ -757,6 +776,7 @@ simple_wallet::simple_wallet() 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("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>")); m_cmd_binder.set_handler("check_tx_key", boost::bind(&simple_wallet::check_tx_key, this, _1), tr("Check amount going to <address> in <txid>")); @@ -768,6 +788,7 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("set_tx_note", boost::bind(&simple_wallet::set_tx_note, this, _1), tr("Set an arbitrary string note for a txid")); m_cmd_binder.set_handler("get_tx_note", boost::bind(&simple_wallet::get_tx_note, this, _1), tr("Get a string note for a txid")); m_cmd_binder.set_handler("status", boost::bind(&simple_wallet::status, this, _1), tr("Show wallet status information")); + m_cmd_binder.set_handler("wallet_info", boost::bind(&simple_wallet::wallet_info, this, _1), tr("Show wallet information")); m_cmd_binder.set_handler("sign", boost::bind(&simple_wallet::sign, this, _1), tr("Sign the contents of a file")); m_cmd_binder.set_handler("verify", boost::bind(&simple_wallet::verify, this, _1), tr("Verify a signature on the contents of a file")); m_cmd_binder.set_handler("export_key_images", boost::bind(&simple_wallet::export_key_images, this, _1), tr("Export a signed set of key images")); @@ -1026,6 +1047,13 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) fail_msg_writer() << tr("Electrum-style word list failed verification"); return false; } + + auto pwd_container = tools::password_container::prompt(false, tr("Enter seed encryption passphrase, empty if none")); + if (std::cin.eof() || !pwd_container) + return false; + std::string seed_pass = pwd_container->password(); + if (!seed_pass.empty()) + m_recovery_key = cryptonote::decrypt_key(m_recovery_key, seed_pass); } if (!m_generate_from_view_key.empty()) { @@ -1680,9 +1708,18 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm) catch (const std::exception& e) { fail_msg_writer() << tr("failed to load wallet: ") << e.what(); - // only suggest removing cache if the password was actually correct - if (m_wallet && m_wallet->verify_password(password)) - fail_msg_writer() << boost::format(tr("You may want to remove the file \"%s\" and try again")) % m_wallet_file; + if (m_wallet) + { + // only suggest removing cache if the password was actually correct + bool password_is_correct = false; + try + { + password_is_correct = m_wallet->verify_password(password); + } + catch (...) { } // guard against I/O errors + if (password_is_correct) + fail_msg_writer() << boost::format(tr("You may want to remove the file \"%s\" and try again")) % m_wallet_file; + } return false; } success_msg_writer() << @@ -2329,7 +2366,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri } } - size_t fake_outs_count; + size_t fake_outs_count = 0; if(local_args.size() > 0) { size_t ring_size; if(!epee::string_tools::get_xtype_from_string(ring_size, local_args[0])) @@ -2906,7 +2943,7 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a std::vector<std::string> local_args = args_; - size_t fake_outs_count; + size_t fake_outs_count = 0; if(local_args.size() > 0) { size_t ring_size; if(!epee::string_tools::get_xtype_from_string(ring_size, local_args[0])) @@ -3241,7 +3278,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; @@ -3474,6 +3511,9 @@ bool simple_wallet::submit_transfer(const std::vector<std::string> &args_) catch (const tools::error::tx_rejected& e) { fail_msg_writer() << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status(); + std::string reason = e.reason(); + if (!reason.empty()) + fail_msg_writer() << tr("Reason: ") << reason; } catch (const tools::error::tx_sum_overflow& e) { @@ -4507,6 +4547,15 @@ bool simple_wallet::status(const std::vector<std::string> &args) return true; } //---------------------------------------------------------------------------------------------------- +bool simple_wallet::wallet_info(const std::vector<std::string> &args) +{ + message_writer() << tr("Filename: ") << m_wallet->get_wallet_file(); + message_writer() << tr("Address: ") << m_wallet->get_account().get_public_address_str(m_wallet->testnet()); + message_writer() << tr("Watch only: ") << (m_wallet->watch_only() ? tr("Yes") : tr("No")); + message_writer() << tr("Testnet: ") << (m_wallet->testnet() ? tr("Yes") : tr("No")); + return true; +} +//---------------------------------------------------------------------------------------------------- bool simple_wallet::sign(const std::vector<std::string> &args) { if (args.size() != 1) diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 079fae9f5..3b29e3ca2 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -97,6 +97,7 @@ namespace cryptonote bool viewkey(const std::vector<std::string> &args = std::vector<std::string>()); bool spendkey(const std::vector<std::string> &args = std::vector<std::string>()); bool seed(const std::vector<std::string> &args = std::vector<std::string>()); + bool encrypted_seed(const std::vector<std::string> &args = std::vector<std::string>()); /*! * \brief Sets seed language. @@ -165,6 +166,7 @@ namespace cryptonote bool set_tx_note(const std::vector<std::string> &args); bool get_tx_note(const std::vector<std::string> &args); bool status(const std::vector<std::string> &args); + bool wallet_info(const std::vector<std::string> &args); bool set_default_priority(const std::vector<std::string> &args); bool sign(const std::vector<std::string> &args); bool verify(const std::vector<std::string> &args); @@ -185,6 +187,7 @@ namespace cryptonote bool accept_loaded_tx(const tools::wallet2::signed_tx_set &txs); bool print_ring_members(const std::vector<tools::wallet2::pending_tx>& ptx_vector, std::ostream& ostr); std::string get_prompt() const; + bool print_seed(bool encrypted); /*! * \brief Prints the seed with a nice message diff --git a/src/version.cmake b/src/version.cmake index 623d3cf1f..45a97cd20 100644 --- a/src/version.cmake +++ b/src/version.cmake @@ -36,7 +36,7 @@ if(RET) message(WARNING "Cannot determine current commit. Make sure that you are building either from a Git working tree or from a source archive.") set(VERSIONTAG "unknown") - configure_file("src/version.h.in" "${TO}") + configure_file("src/version.cpp.in" "${TO}") else() message(STATUS "You are currently on commit ${COMMIT}") @@ -59,5 +59,5 @@ else() endif() endif() - configure_file("src/version.h.in" "${TO}") + configure_file("src/version.cpp.in" "${TO}") endif() diff --git a/src/version.cpp.in b/src/version.cpp.in new file mode 100644 index 000000000..d1444f867 --- /dev/null +++ b/src/version.cpp.in @@ -0,0 +1,11 @@ +#define DEF_MONERO_VERSION_TAG "@VERSIONTAG@" +#define DEF_MONERO_VERSION "0.11.0.0" +#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; +const char* const MONERO_VERSION_FULL = DEF_MONERO_VERSION_FULL; diff --git a/src/version.h b/src/version.h new file mode 100644 index 000000000..d1d06c790 --- /dev/null +++ b/src/version.h @@ -0,0 +1,6 @@ +#pragma once + +extern const char* const MONERO_VERSION_TAG; +extern const char* const MONERO_VERSION; +extern const char* const MONERO_RELEASE_NAME; +extern const char* const MONERO_VERSION_FULL; diff --git a/src/version.h.in b/src/version.h.in deleted file mode 100644 index 281b52db4..000000000 --- a/src/version.h.in +++ /dev/null @@ -1,4 +0,0 @@ -#define MONERO_VERSION_TAG "@VERSIONTAG@" -#define MONERO_VERSION "0.11.0.0" -#define MONERO_RELEASE_NAME "Helium Hydra" -#define MONERO_VERSION_FULL MONERO_VERSION "-" MONERO_VERSION_TAG diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt index 639080051..fe87d0de1 100644 --- a/src/wallet/CMakeLists.txt +++ b/src/wallet/CMakeLists.txt @@ -84,7 +84,6 @@ target_link_libraries(wallet ${Boost_REGEX_LIBRARY} PRIVATE ${EXTRA_LIBRARIES}) -add_dependencies(wallet version) if (NOT BUILD_GUI_DEPS) set(wallet_rpc_sources @@ -110,13 +109,13 @@ if (NOT BUILD_GUI_DEPS) cryptonote_core cncrypto common + version ${Boost_CHRONO_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_THREAD_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_LIBRARIES}) - add_dependencies(wallet_rpc_server version) set_property(TARGET wallet_rpc_server PROPERTY OUTPUT_NAME "monero-wallet-rpc") diff --git a/src/wallet/api/address_book.cpp b/src/wallet/api/address_book.cpp index 28f835ebd..9605047b7 100644 --- a/src/wallet/api/address_book.cpp +++ b/src/wallet/api/address_book.cpp @@ -42,7 +42,7 @@ namespace Monero { AddressBook::~AddressBook() {} AddressBookImpl::AddressBookImpl(WalletImpl *wallet) - : m_wallet(wallet) {} + : m_wallet(wallet), m_errorCode(Status_Ok) {} bool AddressBookImpl::addRow(const std::string &dst_addr , const std::string &payment_id_str, const std::string &description) { @@ -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/api/wallet.cpp b/src/wallet/api/wallet.cpp index 7afc1f449..9cd72b543 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -303,7 +303,7 @@ WalletImpl::~WalletImpl() // Pause refresh thread - prevents refresh from starting again pauseRefresh(); // Close wallet - stores cache and stops ongoing refresh operation - close(); + close(false); // do not store wallet as part of the closing activities // Stop refresh thread stopRefresh(); delete m_wallet2Callback; @@ -566,19 +566,21 @@ bool WalletImpl::recover(const std::string &path, const std::string &seed) return m_status == Status_Ok; } -bool WalletImpl::close() +bool WalletImpl::close(bool store) { bool result = false; LOG_PRINT_L1("closing wallet..."); try { - // Do not store wallet with invalid status - // Status Critical refers to errors on opening or creating wallets. - if (status() != Status_Critical) - m_wallet->store(); - else - LOG_ERROR("Status_Critical - not storing wallet"); - LOG_PRINT_L1("wallet::store done"); + if (store) { + // Do not store wallet with invalid status + // Status Critical refers to errors on opening or creating wallets. + if (status() != Status_Critical) + m_wallet->store(); + else + LOG_ERROR("Status_Critical - not storing wallet"); + LOG_PRINT_L1("wallet::store done"); + } LOG_PRINT_L1("Calling wallet::stop..."); m_wallet->stop(); LOG_PRINT_L1("wallet::stop done"); diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 8190c7873..1e3d1e600 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -63,7 +63,7 @@ public: const std::string &address_string, const std::string &viewkey_string, const std::string &spendkey_string = ""); - bool close(); + bool close(bool store = true); std::string seed() const; std::string getSeedLanguage() const; void setSeedLanguage(const std::string &arg); @@ -153,7 +153,6 @@ private: std::string m_password; TransactionHistoryImpl * m_history; bool m_trustedDaemon; - WalletListener * m_walletListener; Wallet2CallbackImpl * m_wallet2Callback; AddressBookImpl * m_addressBook; diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp index a23533530..897137d35 100644 --- a/src/wallet/api/wallet_manager.cpp +++ b/src/wallet/api/wallet_manager.cpp @@ -102,10 +102,12 @@ Wallet *WalletManagerImpl::createWalletFromKeys(const std::string &path, return wallet; } -bool WalletManagerImpl::closeWallet(Wallet *wallet) +bool WalletManagerImpl::closeWallet(Wallet *wallet, bool store) { WalletImpl * wallet_ = dynamic_cast<WalletImpl*>(wallet); - bool result = wallet_->close(); + if (!wallet_) + return false; + bool result = wallet_->close(store); if (!result) { m_errorString = wallet_->errorString(); } else { diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h index aa6ea439e..8455f0f16 100644 --- a/src/wallet/api/wallet_manager.h +++ b/src/wallet/api/wallet_manager.h @@ -48,7 +48,7 @@ public: const std::string &addressString, const std::string &viewKeyString, const std::string &spendKeyString = ""); - virtual bool closeWallet(Wallet *wallet); + virtual bool closeWallet(Wallet *wallet, bool store = true); bool walletExists(const std::string &path); bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool watch_only) const; std::vector<std::string> findWallets(const std::string &path); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index f72d281c7..08e1d2a09 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; @@ -289,6 +290,13 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, return false; } restore_deterministic_wallet = true; + + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, seed_passphrase, std::string, String, false, std::string()); + if (field_seed_passphrase_found) + { + if (!field_seed_passphrase.empty()) + recovery_key = cryptonote::decrypt_key(recovery_key, field_seed_passphrase); + } } GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, address, std::string, String, false, std::string()); @@ -376,7 +384,11 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, cryptonote::account_public_address address2; bool has_payment_id; crypto::hash8 new_payment_id; - get_account_integrated_address_from_str(address2, has_payment_id, new_payment_id, testnet, field_address); + if (!get_account_integrated_address_from_str(address2, has_payment_id, new_payment_id, testnet, field_address)) + { + tools::fail_msg_writer() << tools::wallet2::tr("failed to parse address: ") << field_address; + return false; + } address.m_spend_public_key = address2.m_spend_public_key; } wallet->generate(field_filename, field_password, address, viewkey); @@ -419,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 @@ -502,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; @@ -520,7 +547,7 @@ bool wallet2::is_deterministic() const return keys_deterministic; } //---------------------------------------------------------------------------------------------------- -bool wallet2::get_seed(std::string& electrum_words) const +bool wallet2::get_seed(std::string& electrum_words, const std::string &passphrase) const { bool keys_deterministic = is_deterministic(); if (!keys_deterministic) @@ -534,7 +561,10 @@ bool wallet2::get_seed(std::string& electrum_words) const return false; } - crypto::ElectrumWords::bytes_to_words(get_account().get_keys().m_spend_secret_key, electrum_words, seed_language); + crypto::secret_key key = get_account().get_keys().m_spend_secret_key; + if (!passphrase.empty()) + key = cryptonote::encrypt_key(key, passphrase); + crypto::ElectrumWords::bytes_to_words(key, electrum_words, seed_language); return true; } @@ -577,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) @@ -635,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 @@ -673,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); @@ -689,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); } } } @@ -795,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); } } } @@ -841,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)) @@ -857,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) @@ -879,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); @@ -912,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) @@ -926,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); @@ -1128,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; @@ -1147,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 @@ -1233,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(); @@ -1529,23 +1520,22 @@ void wallet2::update_pool_state(bool refreshed) { if (res.txs.size() == txids.size()) { - size_t n = 0; - for (const auto &txid: txids) + for (const auto &tx_entry: res.txs) { - // might have just been put in a block - if (res.txs[n].in_pool) + if (tx_entry.in_pool) { cryptonote::transaction tx; cryptonote::blobdata bd; crypto::hash tx_hash, tx_prefix_hash; - if (epee::string_tools::parse_hexstr_to_binbuff(res.txs[n].as_hex, bd)) + if (epee::string_tools::parse_hexstr_to_binbuff(tx_entry.as_hex, bd)) { if (cryptonote::parse_and_validate_tx_from_blob(bd, tx, tx_hash, tx_prefix_hash)) { - if (tx_hash == txid) + const std::vector<crypto::hash>::const_iterator i = std::find(txids.begin(), txids.end(), tx_hash); + if (i != txids.end()) { - process_new_transaction(txid, tx, std::vector<uint64_t>(), 0, time(NULL), false, true); - m_scanned_pool_txs[0].insert(txid); + process_new_transaction(tx_hash, tx, std::vector<uint64_t>(), 0, time(NULL), false, true); + m_scanned_pool_txs[0].insert(tx_hash); if (m_scanned_pool_txs[0].size() > 5000) { std::swap(m_scanned_pool_txs[0], m_scanned_pool_txs[1]); @@ -1554,7 +1544,7 @@ void wallet2::update_pool_state(bool refreshed) } else { - LOG_PRINT_L0("Mismatched txids when processing unconfimed txes from pool"); + MERROR("Got txid " << tx_hash << " which we did not ask for"); } } else @@ -1564,14 +1554,13 @@ void wallet2::update_pool_state(bool refreshed) } else { - LOG_PRINT_L0("Failed to parse tx " << txid); + LOG_PRINT_L0("Failed to parse transaction from daemon"); } } else { - LOG_PRINT_L1("Tx " << txid << " was in pool, but is no more"); + LOG_PRINT_L1("Transaction from daemon was in pool, but is no more"); } - ++n; } } else @@ -1787,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) @@ -1817,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(); ) @@ -2562,13 +2558,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 @@ -2583,6 +2615,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 @@ -2645,10 +2679,11 @@ void wallet2::store_to(const std::string &path, const std::string &password) // if we here, main wallet file is saved and we only need to save keys and address files if (!same_file) { prepare_file_names(path); - store_keys(m_keys_file, password, false); + bool r = store_keys(m_keys_file, password, false); + THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file); // save address to the new file const std::string address_file = m_wallet_file + ".address.txt"; - bool r = file_io_utils::save_string_to_file(address_file, m_account.get_public_address_str(m_testnet)); + r = file_io_utils::save_string_to_file(address_file, m_account.get_public_address_str(m_testnet)); THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_wallet_file); // remove old wallet file r = boost::filesystem::remove(old_file); @@ -3090,7 +3125,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)) @@ -3105,7 +3140,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; @@ -3154,7 +3189,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()) @@ -4338,7 +4373,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"); @@ -4437,12 +4473,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); @@ -4616,6 +4648,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; } } } @@ -5164,10 +5197,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; } } @@ -5175,7 +5207,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) @@ -5381,6 +5413,9 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag } spent = 0; unspent = 0; + std::unordered_set<crypto::hash> spent_txids; // For each spent key image, search for a tx in m_transfers that uses it as input. + std::vector<size_t> swept_transfers; // If such a spending tx wasn't found in m_transfers, this means the spending tx + // was created by sweep_all, so we can't know the spent height and other detailed info. for(size_t i = 0; i < m_transfers.size(); ++i) { transfer_details &td = m_transfers[i]; @@ -5391,8 +5426,145 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag unspent += amount; LOG_PRINT_L2("Transfer " << i << ": " << print_money(amount) << " (" << td.m_global_output_index << "): " << (td.m_spent ? "spent" : "unspent") << " (key image " << req.key_images[i] << ")"); + + if (i < daemon_resp.spent_status.size() && daemon_resp.spent_status[i] == COMMAND_RPC_IS_KEY_IMAGE_SPENT::SPENT_IN_BLOCKCHAIN) + { + bool is_spent_tx_found = false; + for (auto it = m_transfers.rbegin(); &(*it) != &td; ++it) + { + bool is_spent_tx = false; + for(const cryptonote::txin_v& in : it->m_tx.vin) + { + if(in.type() == typeid(cryptonote::txin_to_key) && td.m_key_image == boost::get<cryptonote::txin_to_key>(in).k_image) + { + is_spent_tx = true; + break; + } + } + if (is_spent_tx) + { + is_spent_tx_found = true; + spent_txids.insert(it->m_txid); + break; + } + } + + if (!is_spent_tx_found) + swept_transfers.push_back(i); + } } MDEBUG("Total: " << print_money(spent) << " spent, " << print_money(unspent) << " unspent"); + + if (check_spent) + { + // query outgoing txes + COMMAND_RPC_GET_TRANSACTIONS::request gettxs_req; + COMMAND_RPC_GET_TRANSACTIONS::response gettxs_res; + gettxs_req.decode_as_json = false; + for (const crypto::hash& spent_txid : spent_txids) + gettxs_req.txs_hashes.push_back(epee::string_tools::pod_to_hex(spent_txid)); + m_daemon_rpc_mutex.lock(); + bool r = epee::net_utils::invoke_http_json("/gettransactions", gettxs_req, gettxs_res, m_http_client, rpc_timeout); + m_daemon_rpc_mutex.unlock(); + THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions"); + THROW_WALLET_EXCEPTION_IF(gettxs_res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions"); + THROW_WALLET_EXCEPTION_IF(gettxs_res.txs.size() != spent_txids.size(), error::wallet_internal_error, + "daemon returned wrong response for gettransactions, wrong count = " + std::to_string(gettxs_res.txs.size()) + ", expected " + std::to_string(spent_txids.size())); + + // process each outgoing tx + auto spent_txid = spent_txids.begin(); + for (const COMMAND_RPC_GET_TRANSACTIONS::entry& e : gettxs_res.txs) + { + THROW_WALLET_EXCEPTION_IF(e.in_pool, error::wallet_internal_error, "spent tx isn't supposed to be in txpool"); + + // parse tx + cryptonote::blobdata bd; + THROW_WALLET_EXCEPTION_IF(!epee::string_tools::parse_hexstr_to_binbuff(e.as_hex, bd), error::wallet_internal_error, "parse_hexstr_to_binbuff failed"); + cryptonote::transaction spent_tx; + crypto::hash spnet_txid_parsed, spent_txid_prefix; + THROW_WALLET_EXCEPTION_IF(!cryptonote::parse_and_validate_tx_from_blob(bd, spent_tx, spnet_txid_parsed, spent_txid_prefix), error::wallet_internal_error, "parse_and_validate_tx_from_blob failed"); + THROW_WALLET_EXCEPTION_IF(*spent_txid != spnet_txid_parsed, error::wallet_internal_error, "parsed txid mismatch"); + + // get received (change) amount + uint64_t tx_money_got_in_outs = 0; + const cryptonote::account_keys& keys = m_account.get_keys(); + const crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(spent_tx); + crypto::key_derivation derivation; + generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation); + size_t output_index = 0; + for (const cryptonote::tx_out& out : spent_tx.vout) + { + 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 (tx_scan_info.money_transfered == 0) + { + rct::key 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 += tx_scan_info.money_transfered; + } + ++output_index; + } + + // get spent amount + uint64_t tx_money_spent_in_ins = 0; + for (const cryptonote::txin_v& in : spent_tx.vin) + { + if (in.type() != typeid(cryptonote::txin_to_key)) + continue; + auto it = m_key_images.find(boost::get<cryptonote::txin_to_key>(in).k_image); + if (it != m_key_images.end()) + { + const transfer_details& td = m_transfers[it->second]; + uint64_t amount = boost::get<cryptonote::txin_to_key>(in).amount; + if (amount > 0) + { + THROW_WALLET_EXCEPTION_IF(amount != td.amount(), error::wallet_internal_error, + std::string("Inconsistent amount in tx input: got ") + print_money(amount) + + std::string(", expected ") + print_money(td.amount())); + } + amount = td.amount(); + tx_money_spent_in_ins += amount; + + LOG_PRINT_L0("Spent money: " << print_money(amount) << ", with tx: " << *spent_txid); + set_spent(it->second, e.block_height); + if (m_callback) + m_callback->on_money_spent(e.block_height, *spent_txid, spent_tx, amount, spent_tx); + } + } + + // create outgoing payment + process_outgoing(*spent_txid, spent_tx, e.block_height, e.block_timestamp, tx_money_spent_in_ins, tx_money_got_in_outs); + + // erase corresponding incoming payment + for (auto j = m_payments.begin(); j != m_payments.end(); ++j) + { + if (j->second.m_tx_hash == *spent_txid) + { + m_payments.erase(j); + break; + } + } + + ++spent_txid; + } + + for (size_t n : swept_transfers) + { + const transfer_details& td = m_transfers[n]; + confirmed_transfer_details pd; + pd.m_change = (uint64_t)-1; // cahnge is unknown + pd.m_amount_in = pd.m_amount_out = td.amount(); // fee is unknown + std::string err; + pd.m_block_height = get_daemon_blockchain_height(err); // spent block height is unknown, so hypothetically set to the highest + crypto::hash spent_txid = crypto::rand<crypto::hash>(); // spent txid is unknown, so hypothetically set to random + m_confirmed_txs.insert(std::make_pair(spent_txid, pd)); + } + } + return m_transfers[signed_key_images.size() - 1].m_block_height; } wallet2::payment_container wallet2::export_payments() const @@ -5421,20 +5593,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); } @@ -5536,7 +5716,7 @@ std::string wallet2::decrypt(const std::string &ciphertext, const crypto::secret crypto::secret_key_to_public_key(skey, pkey); const crypto::signature &signature = *(const crypto::signature*)&ciphertext[ciphertext.size() - sizeof(crypto::signature)]; THROW_WALLET_EXCEPTION_IF(!crypto::check_signature(hash, pkey, signature), - error::wallet_internal_error, "Failed to authenticate criphertext"); + error::wallet_internal_error, "Failed to authenticate ciphertext"); } crypto::chacha8(ciphertext.data() + sizeof(iv), ciphertext.size() - prefix_size, key, iv, &plaintext[0]); return plaintext; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index adf03abcc..1dff14a95 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) {} }; @@ -363,7 +410,7 @@ namespace tools * \brief Checks if deterministic wallet */ bool is_deterministic() const; - bool get_seed(std::string& electrum_words) const; + bool get_seed(std::string& electrum_words, const std::string &passphrase = std::string()) const; /*! * \brief Gets the seed language */ @@ -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; @@ -588,8 +647,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 +709,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 +723,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 +732,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; @@ -716,7 +778,7 @@ namespace tools 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/wallet2_api.h b/src/wallet/wallet2_api.h index 8da8c62eb..7a5e01af7 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -663,7 +663,7 @@ struct WalletManager * \param wallet previously opened / created wallet instance * \return None */ - virtual bool closeWallet(Wallet *wallet) = 0; + virtual bool closeWallet(Wallet *wallet, bool store = true) = 0; /* * ! checks if wallet with the given name already exists diff --git a/src/wallet/wallet_args.cpp b/src/wallet/wallet_args.cpp index 34c5a2a5d..22cfcc269 100644 --- a/src/wallet/wallet_args.cpp +++ b/src/wallet/wallet_args.cpp @@ -84,6 +84,7 @@ namespace wallet_args #endif const command_line::arg_descriptor<std::string> arg_log_level = {"log-level", "0-4 or categories", ""}; + const command_line::arg_descriptor<std::size_t> arg_max_log_file_size = {"max-log-file-size", "Specify maximum log file size [B]", MAX_LOG_FILE_SIZE}; const command_line::arg_descriptor<uint32_t> arg_max_concurrency = {"max-concurrency", wallet_args::tr("Max number of threads to use for a parallel job"), DEFAULT_MAX_CONCURRENCY}; const command_line::arg_descriptor<std::string> arg_log_file = {"log-file", wallet_args::tr("Specify log file"), ""}; const command_line::arg_descriptor<std::string> arg_config_file = {"config-file", wallet_args::tr("Config file"), "", true}; @@ -99,8 +100,9 @@ namespace wallet_args command_line::add_arg(desc_general, command_line::arg_help); command_line::add_arg(desc_general, command_line::arg_version); - command_line::add_arg(desc_params, arg_log_file, ""); + command_line::add_arg(desc_params, arg_log_file); command_line::add_arg(desc_params, arg_log_level); + command_line::add_arg(desc_params, arg_max_log_file_size); command_line::add_arg(desc_params, arg_max_concurrency); command_line::add_arg(desc_params, arg_config_file); @@ -114,6 +116,21 @@ namespace wallet_args auto parser = po::command_line_parser(argc, argv).options(desc_all).positional(positional_options); po::store(parser.run(), vm); + if (command_line::get_arg(vm, command_line::arg_help)) + { + tools::msg_writer() << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL; + tools::msg_writer() << wallet_args::tr("This is the command line monero wallet. It needs to connect to a monero\n" + "daemon to work correctly.") << ENDL; + tools::msg_writer() << wallet_args::tr("Usage:") << ENDL << " " << usage; + tools::msg_writer() << desc_all; + return false; + } + else if (command_line::get_arg(vm, command_line::arg_version)) + { + tools::msg_writer() << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")"; + return false; + } + if(command_line::has_arg(vm, arg_config_file)) { std::string config = command_line::get_arg(vm, arg_config_file); @@ -141,27 +158,12 @@ namespace wallet_args log_path = command_line::get_arg(vm, arg_log_file); else log_path = mlog_get_default_log_path(default_log_name); - mlog_configure(log_path, log_to_console); + mlog_configure(log_path, log_to_console, command_line::get_arg(vm, arg_max_log_file_size)); if (!vm["log-level"].defaulted()) { mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str()); } - if (command_line::get_arg(vm, command_line::arg_help)) - { - tools::msg_writer() << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL; - tools::msg_writer() << wallet_args::tr("This is the command line monero wallet. It needs to connect to a monero\n" - "daemon to work correctly.") << ENDL; - tools::msg_writer() << wallet_args::tr("Usage:") << ENDL << " " << usage; - tools::msg_writer() << desc_all; - return boost::none; - } - else if (command_line::get_arg(vm, command_line::arg_version)) - { - tools::msg_writer() << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")"; - return boost::none; - } - if(command_line::has_arg(vm, arg_max_concurrency)) tools::set_max_concurrency(command_line::get_arg(vm, arg_max_concurrency)); diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 773d12775..46b092376 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -27,6 +27,7 @@ // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers +#include <boost/format.hpp> #include <boost/asio/ip/address.hpp> #include <boost/filesystem/operations.hpp> #include <cstdint> @@ -37,7 +38,6 @@ using namespace epee; #include "wallet/wallet_args.h" #include "common/command_line.h" #include "common/i18n.h" -#include "common/util.h" #include "cryptonote_basic/cryptonote_format_utils.h" #include "cryptonote_basic/account.h" #include "wallet_rpc_server_commands_defs.h" @@ -70,18 +70,12 @@ namespace tools } //------------------------------------------------------------------------------------------------------------------------------ - wallet_rpc_server::wallet_rpc_server():m_wallet(NULL), rpc_login_filename(), m_stop(false), m_trusted_daemon(false) + wallet_rpc_server::wallet_rpc_server():m_wallet(NULL), rpc_login_file(), m_stop(false), m_trusted_daemon(false), m_vm(NULL) { } //------------------------------------------------------------------------------------------------------------------------------ wallet_rpc_server::~wallet_rpc_server() { - try - { - boost::system::error_code ec{}; - boost::filesystem::remove(rpc_login_filename, ec); - } - catch (...) {} } //------------------------------------------------------------------------------------------------------------------------------ void wallet_rpc_server::set_wallet(wallet2 *cr) @@ -160,7 +154,15 @@ namespace tools #else #define MKDIR(path, mode) mkdir(path, mode) #endif - MKDIR(m_wallet_dir.c_str(), 0700); + if (MKDIR(m_wallet_dir.c_str(), 0700) < 0) + { +#ifdef _WIN32 + LOG_ERROR(tr("Failed to create directory ") + m_wallet_dir); +#else + LOG_ERROR((boost::format(tr("Failed to create directory %s: %s")) % m_wallet_dir % strerror(errno)).str()); +#endif + return false; + } } if (disable_auth) @@ -182,34 +184,32 @@ namespace tools default_rpc_username, string_encoding::base64_encode(rand_128bit.data(), rand_128bit.size()) ); + + std::string temp = "monero-wallet-rpc." + bind_port + ".login"; + rpc_login_file = tools::private_file::create(temp); + if (!rpc_login_file.handle()) + { + LOG_ERROR(tr("Failed to create file ") << temp << tr(". Check permissions or remove file")); + return false; + } + std::fputs(http_login->username.c_str(), rpc_login_file.handle()); + std::fputc(':', rpc_login_file.handle()); + std::fputs(http_login->password.c_str(), rpc_login_file.handle()); + std::fflush(rpc_login_file.handle()); + if (std::ferror(rpc_login_file.handle())) + { + LOG_ERROR(tr("Error writing to file ") << temp); + return false; + } + LOG_PRINT_L0(tr("RPC username/password is stored in file ") << temp); } - else + else // chosen user/pass { http_login.emplace( std::move(rpc_config->login->username), std::move(rpc_config->login->password).password() ); } assert(bool(http_login)); - - std::string temp = "monero-wallet-rpc." + bind_port + ".login"; - const auto cookie = tools::create_private_file(temp); - if (!cookie) - { - LOG_ERROR(tr("Failed to create file ") << temp << tr(". Check permissions or remove file")); - return false; - } - rpc_login_filename.swap(temp); // nothrow guarantee destructor cleanup - temp = rpc_login_filename; - std::fputs(http_login->username.c_str(), cookie.get()); - std::fputc(':', cookie.get()); - std::fputs(http_login->password.c_str(), cookie.get()); - std::fflush(cookie.get()); - if (std::ferror(cookie.get())) - { - LOG_ERROR(tr("Error writing to file ") << temp); - return false; - } - LOG_PRINT_L0(tr("RPC username/password is stored in file ") << temp); } // end auth enabled m_http_client.set_server(walvars->get_daemon_address(), walvars->get_daemon_login()); @@ -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 { @@ -1545,7 +1545,7 @@ namespace tools er.message = "Failed to add address book entry"; return false; } - res.index = m_wallet->get_address_book().size(); + res.index = m_wallet->get_address_book().size() - 1; return true; } //------------------------------------------------------------------------------------------------------------------------------ @@ -1896,7 +1896,15 @@ just_dir: wrpc.send_stop_signal(); }); LOG_PRINT_L0(tools::wallet_rpc_server::tr("Starting wallet rpc server")); - wrpc.run(); + try + { + wrpc.run(); + } + catch (const std::exception &e) + { + LOG_ERROR(tools::wallet_rpc_server::tr("Failed to run wallet: ") << e.what()); + return 1; + } LOG_PRINT_L0(tools::wallet_rpc_server::tr("Stopped wallet rpc server")); try { diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h index dd54222b0..e5ed0a846 100644 --- a/src/wallet/wallet_rpc_server.h +++ b/src/wallet/wallet_rpc_server.h @@ -33,6 +33,7 @@ #include <boost/program_options/options_description.hpp> #include <boost/program_options/variables_map.hpp> #include <string> +#include "common/util.h" #include "net/http_server_impl_base.h" #include "wallet_rpc_server_commands_defs.h" #include "wallet2.h" @@ -154,7 +155,7 @@ namespace tools wallet2 *m_wallet; std::string m_wallet_dir; - std::string rpc_login_filename; + tools::private_file rpc_login_file; std::atomic<bool> m_stop; bool m_trusted_daemon; epee::net_utils::http::http_simple_client m_http_client; diff --git a/tests/core_proxy/CMakeLists.txt b/tests/core_proxy/CMakeLists.txt index d22fecc9c..d2dc93cf0 100644 --- a/tests/core_proxy/CMakeLists.txt +++ b/tests/core_proxy/CMakeLists.txt @@ -40,6 +40,7 @@ target_link_libraries(core_proxy cryptonote_core cryptonote_protocol p2p + version epee ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_LIBRARIES}) diff --git a/tests/core_proxy/core_proxy.cpp b/tests/core_proxy/core_proxy.cpp index 366937e1d..a0be3db96 100644 --- a/tests/core_proxy/core_proxy.cpp +++ b/tests/core_proxy/core_proxy.cpp @@ -229,10 +229,9 @@ bool tests::proxy_core::get_short_chain_history(std::list<crypto::hash>& ids) { return true; } -bool tests::proxy_core::get_blockchain_top(uint64_t& height, crypto::hash& top_id) { +void tests::proxy_core::get_blockchain_top(uint64_t& height, crypto::hash& top_id) { height = 0; top_id = get_block_hash(m_genesis); - return true; } bool tests::proxy_core::init(const boost::program_options::variables_map& /*vm*/) { @@ -256,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); } @@ -266,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 85518612a..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) { } }; @@ -74,7 +74,7 @@ namespace tests bool get_short_chain_history(std::list<crypto::hash>& ids); bool get_stat_info(cryptonote::core_stat_info& st_inf){return true;} bool have_block(const crypto::hash& id); - bool get_blockchain_top(uint64_t& height, crypto::hash& top_id); + void get_blockchain_top(uint64_t& height, crypto::hash& top_id); bool handle_incoming_tx(const cryptonote::blobdata& tx_blob, cryptonote::tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay); bool handle_incoming_txs(const std::list<cryptonote::blobdata>& tx_blobs, std::vector<cryptonote::tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay); bool handle_incoming_block(const cryptonote::blobdata& block_blob, cryptonote::block_verification_context& bvc, bool update_miner_blocktemplate = true); diff --git a/tests/core_tests/CMakeLists.txt b/tests/core_tests/CMakeLists.txt index c1d3161bc..a24bd4fce 100644 --- a/tests/core_tests/CMakeLists.txt +++ b/tests/core_tests/CMakeLists.txt @@ -65,6 +65,7 @@ target_link_libraries(coretests PRIVATE cryptonote_core p2p + version epee ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_LIBRARIES}) diff --git a/tests/core_tests/rct.cpp b/tests/core_tests/rct.cpp index 21638354d..b546e4407 100644 --- a/tests/core_tests/rct.cpp +++ b/tests/core_tests/rct.cpp @@ -484,8 +484,9 @@ bool gen_rct_tx_pre_rct_altered_extra::generate(std::vector<test_event_entry>& e const int mixin = 2; const int out_idx[] = {0, -1}; const uint64_t amount_paid = 10000; + bool failed = false; return generate_with(events, out_idx, mixin, amount_paid, false, - NULL, [](transaction &tx) {std::string extra_nonce; crypto::hash pid = cryptonote::null_hash; set_payment_id_to_tx_extra_nonce(extra_nonce, pid); add_extra_nonce_to_tx_extra(tx.extra, extra_nonce);}); + 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 @@ -493,7 +494,8 @@ bool gen_rct_tx_rct_altered_extra::generate(std::vector<test_event_entry>& event const int mixin = 2; const int out_idx[] = {1, -1}; const uint64_t amount_paid = 10000; + bool failed = false; return generate_with(events, out_idx, mixin, amount_paid, false, - NULL, [](transaction &tx) {std::string extra_nonce; crypto::hash pid = cryptonote::null_hash; set_payment_id_to_tx_extra_nonce(extra_nonce, pid); add_extra_nonce_to_tx_extra(tx.extra, extra_nonce);}); + 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/libwallet_api_tests/CMakeLists.txt b/tests/libwallet_api_tests/CMakeLists.txt index 51375440b..4c5542d91 100644 --- a/tests/libwallet_api_tests/CMakeLists.txt +++ b/tests/libwallet_api_tests/CMakeLists.txt @@ -40,6 +40,7 @@ add_executable(libwallet_api_tests target_link_libraries(libwallet_api_tests PRIVATE wallet + version epee ${Boost_CHRONO_LIBRARY} ${Boost_SERIALIZATION_LIBRARY} diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index bf0483b0f..d08ab7c75 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -811,7 +811,7 @@ struct MyWalletListener : public Monero::WalletListener void reset() { - send_triggered = receive_triggered = update_triggered = refresh_triggered = false; + send_triggered = receive_triggered = newblock_triggered = update_triggered = refresh_triggered = false; } virtual void moneySpent(const string &txId, uint64_t amount) 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 f5e08b102..53d93fcce 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -27,6 +27,7 @@ # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. set(unit_tests_sources + apply_permutation.cpp address_from_url.cpp ban.cpp base58.cpp @@ -45,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 @@ -78,6 +80,7 @@ target_link_libraries(unit_tests rpc wallet p2p + version epee ${Boost_CHRONO_LIBRARY} ${Boost_THREAD_LIBRARY} diff --git a/tests/unit_tests/apply_permutation.cpp b/tests/unit_tests/apply_permutation.cpp new file mode 100644 index 000000000..a008b74ee --- /dev/null +++ b/tests/unit_tests/apply_permutation.cpp @@ -0,0 +1,74 @@ +// Copyright (c) 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. + +#include "gtest/gtest.h" +#include "common/apply_permutation.h" + +TEST(apply_permutation, empty) +{ + std::vector<int> v = {}; + tools::apply_permutation({}, v); + ASSERT_EQ(v, std::vector<int>({})); +} + +TEST(apply_permutation, reorder) +{ + // 0 1 2 3 4 5 6 + std::vector<int> v = {8, 4, 6, 1, 7, 2, 4}; + tools::apply_permutation({3, 5, 6, 1, 2, 4, 0}, v); + ASSERT_EQ(v, std::vector<int>({1, 2, 4, 4, 6, 7, 8})); +} + +TEST(apply_permutation, bad_size) +{ + std::vector<int> v_large = {8, 4, 6, 1, 7, 2, 4, 9}; + std::vector<int> v_small = {8, 4, 6, 1, 7, 2}; + try + { + tools::apply_permutation({3, 5, 6, 1, 2, 4, 0}, v_large); + ASSERT_FALSE(true); + } + catch (const std::exception &e) {} + try + { + tools::apply_permutation({3, 5, 6, 1, 2, 4, 0}, v_small); + ASSERT_FALSE(true); + } + catch (const std::exception &e) {} +} + +TEST(apply_permutation, bad_permutation) +{ + std::vector<int> v = {8, 4, 6, 1, 7, 2, 4}; + try + { + tools::apply_permutation({3, 5, 6, 1, 2, 4, 1}, v); + ASSERT_FALSE(true); + } + catch (const std::exception &e) {} +} diff --git a/tests/unit_tests/ban.cpp b/tests/unit_tests/ban.cpp index 82ff058b1..b8d57452e 100644 --- a/tests/unit_tests/ban.cpp +++ b/tests/unit_tests/ban.cpp @@ -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;} - bool get_blockchain_top(uint64_t& height, crypto::hash& top_id)const{height=0;top_id=cryptonote::null_hash;return true;} + 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/hardfork.cpp b/tests/unit_tests/hardfork.cpp index c30feb461..2b0904224 100644 --- a/tests/unit_tests/hardfork.cpp +++ b/tests/unit_tests/hardfork.cpp @@ -53,7 +53,7 @@ public: virtual std::string get_db_name() const { return std::string(); } virtual bool lock() { return true; } virtual void unlock() { } - virtual bool batch_start(uint64_t batch_num_blocks=0) { return true; } + virtual bool batch_start(uint64_t batch_num_blocks=0, uint64_t batch_bytes=0) { return true; } virtual void batch_stop() {} virtual void set_batch_transactions(bool) {} virtual void block_txn_start(bool readonly=false) {} 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/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/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/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"/> diff --git a/utils/systemd/monerod.service b/utils/systemd/monerod.service index 12395eb8c..96e88a2d3 100644 --- a/utils/systemd/monerod.service +++ b/utils/systemd/monerod.service @@ -6,12 +6,13 @@ After=network.target User=monero Group=monero WorkingDirectory=~ +RuntimeDirectory=monero Type=forking -PIDFile=/var/run/monerod.pid +PIDFile=/run/monero/monerod.pid ExecStart=/usr/bin/monerod --config-file /etc/monerod.conf \ - --detach --pidfile /var/run/monerod.pid + --detach --pidfile /run/monero/monerod.pid [Install] WantedBy=multi-user.target diff --git a/version.cmake b/version.cmake index 80f1c40b8..75343c381 100644 --- a/version.cmake +++ b/version.cmake @@ -1,32 +1,49 @@ +# 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. + function (write_static_version_header hash) set(VERSIONTAG "${hash}") - configure_file("src/version.h.in" "version/version.h") - add_custom_target(version ALL) + configure_file("src/version.cpp.in" "version.cpp") endfunction () -file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/version") find_package(Git QUIET) if ("$Format:$" STREQUAL "") # We're in a tarball; use hard-coded variables. write_static_version_header("release") elseif (GIT_FOUND OR Git_FOUND) message(STATUS "Found Git: ${GIT_EXECUTABLE}") - set(extra_output) - if (CMAKE_GENERATOR MATCHES "Ninja") - # Ninja will not rerun the command every time if the file doesn't change, - # so inject this bogus output so that it always runs. - set(extra_output "${CMAKE_SOURCE_DIR}/.force-git-version-check") - endif () - add_custom_command( - OUTPUT "${CMAKE_BINARY_DIR}/version/version.h" - ${extra_output} + add_custom_target(genversion ALL COMMAND "${CMAKE_COMMAND}" "-D" "GIT=${GIT_EXECUTABLE}" - "-D" "TO=${CMAKE_BINARY_DIR}/version/version.h" + "-D" "TO=${CMAKE_BINARY_DIR}/version.cpp" "-P" "src/version.cmake" + BYPRODUCTS "${CMAKE_BINARY_DIR}/version.cpp" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}") - add_custom_target(version ALL - DEPENDS "${CMAKE_BINARY_DIR}/version/version.h") else() message(STATUS "WARNING: Git was not found!") write_static_version_header("unknown") |