diff options
30 files changed, 806 insertions, 604 deletions
@@ -86,9 +86,9 @@ See [LICENSE](LICENSE). If you want to help out, see [CONTRIBUTING](CONTRIBUTING.md) for a set of guidelines. -## Scheduled mandatory software upgrades +## Scheduled software upgrades -Monero uses a fixed-schedule mandatory software 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. Mandatory software upgrades occur during the months of March and September. The required software for these upgrades will be available prior to the scheduled date. Please check the repository prior to this date for the proper Monero software version. Below is the historical schedule and the projected schedule for the next upgrade. +Monero uses a fixed-schedule software upgrade (hard fork) mechanism to implement new features. This means that users of Monero (end users and service providers) should run current versions and upgrade their software on a regular schedule. Software upgrades occur during the months of April and October. The required software for these upgrades will be available prior to the scheduled date. Please check the 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. @@ -100,12 +100,13 @@ Dates are provided in the format YYYY-MM-DD. | 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 | | 1546000 | 2018-04-06 | v7 | v0.12.0.0 | v0.12.0.0 | Cryptonight variant 1, ringsize >= 7, sorted inputs +| XXXXXXX | 2018-10-XX | XX | XXXXXXXXX | XXXXXXXXX | X X's indicate that these details have not been determined as of commit date. ## Release staging schedule and protocol -Approximately three months prior to a scheduled mandatory software upgrade, a branch from Master will be created with the new release version tag. Pull requests that address bugs should then be made to both Master and the new release branch. Pull requests that require extensive review and testing (generally, optimizations and new features) should *not* be made to the release branch. +Approximately three months prior to a scheduled software upgrade, a branch from Master will be created with the new release version tag. Pull requests that address bugs should then be made to both Master and the new release branch. Pull requests that require extensive review and testing (generally, optimizations and new features) should *not* be made to the release branch. ## Installing Monero from a package @@ -166,7 +167,7 @@ library archives (`.a`). | Dep | Min. version | Vendored | Debian/Ubuntu pkg | Arch pkg | Fedora | Optional | Purpose | | ------------ | ------------- | -------- | ------------------ | ------------ | ----------------- | -------- | -------------- | | GCC | 4.7.3 | NO | `build-essential` | `base-devel` | `gcc` | NO | | -| CMake | 3.2.0 | NO | `cmake` | `cmake` | `cmake` | NO | | +| CMake | 3.0.0 | NO | `cmake` | `cmake` | `cmake` | NO | | | pkg-config | any | NO | `pkg-config` | `base-devel` | `pkgconf` | NO | | | Boost | 1.58 | NO | `libboost-all-dev` | `boost` | `boost-devel` | NO | C++ libraries | | OpenSSL | basically any | NO | `libssl-dev` | `openssl` | `openssl-devel` | NO | sha256 sum | diff --git a/cmake/Version.cmake b/cmake/Version.cmake index 63b2a6790..439c4c5ae 100644 --- a/cmake/Version.cmake +++ b/cmake/Version.cmake @@ -37,14 +37,16 @@ if ("$Format:$" STREQUAL "") write_static_version_header("release") elseif (GIT_FOUND OR Git_FOUND) message(STATUS "Found Git: ${GIT_EXECUTABLE}") - add_custom_target(genversion ALL + add_custom_command( + OUTPUT "${CMAKE_BINARY_DIR}/version.cpp" COMMAND "${CMAKE_COMMAND}" "-D" "GIT=${GIT_EXECUTABLE}" "-D" "TO=${CMAKE_BINARY_DIR}/version.cpp" "-P" "cmake/GenVersion.cmake" - BYPRODUCTS "${CMAKE_BINARY_DIR}/version.cpp" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}") else() message(STATUS "WARNING: Git was not found!") write_static_version_header("unknown") endif () +add_custom_target(genversion ALL + DEPENDS "${CMAKE_BINARY_DIR}/version.cpp") diff --git a/src/blockchain_utilities/blockchain_blackball.cpp b/src/blockchain_utilities/blockchain_blackball.cpp index 40ce898d9..1243822bb 100644 --- a/src/blockchain_utilities/blockchain_blackball.cpp +++ b/src/blockchain_utilities/blockchain_blackball.cpp @@ -253,7 +253,8 @@ int main(int argc, char* argv[]) return 1; } std::vector<std::unique_ptr<Blockchain>> core_storage(inputs.size()); - tx_memory_pool m_mempool(*(Blockchain*)NULL); + Blockchain *blockchain = NULL; + tx_memory_pool m_mempool(*blockchain); for (size_t n = 0; n < inputs.size(); ++n) { core_storage[n].reset(new Blockchain(m_mempool)); diff --git a/src/common/dns_utils.cpp b/src/common/dns_utils.cpp index 1ecdae8ec..33f60bc3c 100644 --- a/src/common/dns_utils.cpp +++ b/src/common/dns_utils.cpp @@ -230,7 +230,7 @@ DNSResolver::DNSResolver() : m_data(new DNSResolverData()) if (use_dns_public) { for (const auto &ip: dns_public_addr) - ub_ctx_set_fwd(m_data->m_ub_context, ip.c_str()); + ub_ctx_set_fwd(m_data->m_ub_context, string_copy(ip.c_str())); ub_ctx_set_option(m_data->m_ub_context, string_copy("do-udp:"), string_copy("no")); ub_ctx_set_option(m_data->m_ub_context, string_copy("do-tcp:"), string_copy("yes")); } diff --git a/src/common/util.cpp b/src/common/util.cpp index d01da0fb7..7e77e19b1 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -43,6 +43,7 @@ using namespace epee; #include "crypto/crypto.h" #include "util.h" +#include "stack_trace.h" #include "memwipe.h" #include "cryptonote_config.h" #include "net/http_client.h" // epee::net_utils::... @@ -527,7 +528,10 @@ std::string get_nix_version_display_string() { ub_ctx *ctx = ub_ctx_create(); if (!ctx) return false; // cheat a bit, should not happen unless OOM - ub_ctx_zone_add(ctx, "monero", "unbound"); // this calls ub_ctx_finalize first, then errors out with UB_SYNTAX + char *monero = strdup("monero"), *unbound = strdup("unbound"); + ub_ctx_zone_add(ctx, monero, unbound); // this calls ub_ctx_finalize first, then errors out with UB_SYNTAX + free(unbound); + free(monero); // if no threads, bails out early with UB_NOERROR, otherwise fails with UB_AFTERFINAL id already finalized bool with_threads = ub_ctx_async(ctx, 1) != 0; // UB_AFTERFINAL is not defined in public headers, check any error ub_ctx_delete(ctx); @@ -557,10 +561,48 @@ std::string get_nix_version_display_string() } return false; } + +#ifdef STACK_TRACE +#ifdef _WIN32 + // https://stackoverflow.com/questions/1992816/how-to-handle-seg-faults-under-windows + static LONG WINAPI windows_crash_handler(PEXCEPTION_POINTERS pExceptionInfo) + { + tools::log_stack_trace("crashing"); + exit(1); + return EXCEPTION_CONTINUE_SEARCH; + } + static void setup_crash_dump() + { + SetUnhandledExceptionFilter(windows_crash_handler); + } +#else + static void posix_crash_handler(int signal) + { + tools::log_stack_trace(("crashing with fatal signal " + std::to_string(signal)).c_str()); +#ifdef NDEBUG + _exit(1); +#else + abort(); +#endif + } + static void setup_crash_dump() + { + signal(SIGSEGV, posix_crash_handler); + signal(SIGBUS, posix_crash_handler); + signal(SIGILL, posix_crash_handler); + signal(SIGFPE, posix_crash_handler); + } +#endif +#else + static void setup_crash_dump() {} +#endif + bool on_startup() { mlog_configure("", true); + setup_crash_dump(); + sanitize_locale(); #ifdef __GLIBC__ diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 3db516847..f02a1f8d6 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -4365,7 +4365,7 @@ void Blockchain::cancel() } #if defined(PER_BLOCK_CHECKPOINT) -static const char expected_block_hashes_hash[] = "4b553162ee4e7af3c53666506591489c68560b9175e6e941dc96c89f96f0e35c"; +static const char expected_block_hashes_hash[] = "1d3df1a177bd6f752d87c0d7b960e502605742721afb39953265f1e0f7f9b01f"; void Blockchain::load_compiled_in_block_hashes() { const bool testnet = m_nettype == TESTNET; diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index e4a4cb2f1..4d852fc99 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -81,7 +81,7 @@ namespace cryptonote , "Specify data directory" , tools::get_default_data_dir() , {{ &arg_testnet_on, &arg_stagenet_on }} - , [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val) { + , [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val)->std::string { if (testnet_stagenet[0]) return (boost::filesystem::path(val) / "testnet").string(); else if (testnet_stagenet[1]) diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index db4ab9e11..c2252fcc7 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -29,6 +29,7 @@ // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers #include <unordered_set> +#include <random> #include "include_base_utils.h" #include "string_tools.h" using namespace epee; @@ -316,7 +317,7 @@ namespace cryptonote // "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; }); + std::shuffle(shuffled_dsts.begin(), shuffled_dsts.end(), std::default_random_engine(crypto::rand<unsigned int>())); // sort ins by their key image std::vector<size_t> ins_order(sources.size()); @@ -363,7 +364,7 @@ namespace cryptonote uint64_t summary_outs_money = 0; //fill outputs size_t output_index = 0; - for(const tx_destination_entry& dst_entr: destinations) + for(const tx_destination_entry& dst_entr: shuffled_dsts) { CHECK_AND_ASSERT_MES(dst_entr.amount > 0 || tx.version > 1, false, "Destination with wrong amount: " << dst_entr.amount); crypto::key_derivation derivation; diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 0af9737a7..5dfbc1dd4 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -1268,24 +1268,33 @@ namespace cryptonote m_spent_key_images.clear(); m_txpool_size = 0; 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)) - { - MWARNING("Failed to parse tx from txpool, removing"); - remove.push_back(txid); - } - if (!insert_key_images(tx, meta.kept_by_block)) - { - MFATAL("Failed to insert key images from txpool tx"); + + // first add the not kept by block, then the kept by block, + // to avoid rejection due to key image collision + for (int pass = 0; pass < 2; ++pass) + { + const bool kept = pass == 1; + bool r = m_blockchain.for_all_txpool_txes([this, &remove, kept](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd) { + if (!!kept != !!meta.kept_by_block) + return true; + cryptonote::transaction tx; + if (!parse_and_validate_tx_from_blob(*bd, tx)) + { + MWARNING("Failed to parse tx from txpool, removing"); + remove.push_back(txid); + } + if (!insert_key_images(tx, meta.kept_by_block)) + { + MFATAL("Failed to insert key images from txpool tx"); + return false; + } + m_txs_by_fee_and_receive_time.emplace(std::pair<double, time_t>(meta.fee / (double)meta.blob_size, meta.receive_time), txid); + m_txpool_size += meta.blob_size; + return true; + }, true); + if (!r) return false; - } - m_txs_by_fee_and_receive_time.emplace(std::pair<double, time_t>(meta.fee / (double)meta.blob_size, meta.receive_time), txid); - m_txpool_size += meta.blob_size; - return true; - }, true); - if (!r) - return false; + } if (!remove.empty()) { LockedTXN lock(m_blockchain); diff --git a/src/daemon/command_line_args.h b/src/daemon/command_line_args.h index add752029..4673590aa 100644 --- a/src/daemon/command_line_args.h +++ b/src/daemon/command_line_args.h @@ -42,7 +42,7 @@ namespace daemon_args , "Specify configuration file" , (daemonizer::get_default_data_dir() / std::string(CRYPTONOTE_NAME ".conf")).string() , {{ &cryptonote::arg_testnet_on, &cryptonote::arg_stagenet_on }} - , [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val) { + , [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val)->std::string { if (testnet_stagenet[0] && defaulted) return (daemonizer::get_default_data_dir() / "testnet" / std::string(CRYPTONOTE_NAME ".conf")).string(); @@ -57,7 +57,7 @@ namespace daemon_args , "Specify log file" , (daemonizer::get_default_data_dir() / std::string(CRYPTONOTE_NAME ".log")).string() , {{ &cryptonote::arg_testnet_on, &cryptonote::arg_stagenet_on }} - , [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val) { + , [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val)->std::string { if (testnet_stagenet[0] && defaulted) return (daemonizer::get_default_data_dir() / "testnet" / std::string(CRYPTONOTE_NAME ".log")).string(); @@ -102,7 +102,7 @@ namespace daemon_args , "Port for ZMQ RPC server to listen on" , std::to_string(config::ZMQ_RPC_DEFAULT_PORT) , {{ &cryptonote::arg_testnet_on, &cryptonote::arg_stagenet_on }} - , [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val) { + , [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val)->std::string { if (testnet_stagenet[0] && defaulted) return std::to_string(config::testnet::ZMQ_RPC_DEFAULT_PORT); if (testnet_stagenet[1] && defaulted) diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp index 7a89ebc0c..28a7f1366 100644 --- a/src/daemon/command_parser_executor.cpp +++ b/src/daemon/command_parser_executor.cpp @@ -27,6 +27,7 @@ // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "common/dns_utils.h" +#include "version.h" #include "daemon/command_parser_executor.h" #undef MONERO_DEFAULT_LOG_CATEGORY @@ -664,4 +665,10 @@ bool t_command_parser_executor::sync_info(const std::vector<std::string>& args) return m_executor.sync_info(); } +bool t_command_parser_executor::version(const std::vector<std::string>& args) +{ + std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << std::endl; + return true; +} + } // namespace daemonize diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h index 2c09a4748..a70070171 100644 --- a/src/daemon/command_parser_executor.h +++ b/src/daemon/command_parser_executor.h @@ -138,6 +138,8 @@ public: bool relay_tx(const std::vector<std::string>& args); bool sync_info(const std::vector<std::string>& args); + + bool version(const std::vector<std::string>& args); }; } // namespace daemonize diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp index a50dbea69..144603597 100644 --- a/src/daemon/command_server.cpp +++ b/src/daemon/command_server.cpp @@ -280,6 +280,11 @@ t_command_server::t_command_server( , std::bind(&t_command_parser_executor::sync_info, &m_parser, p::_1) , "Print information about the blockchain sync state." ); + m_command_lookup.set_handler( + "version" + , std::bind(&t_command_parser_executor::version, &m_parser, p::_1) + , "Print version information." + ); } bool t_command_server::process_command_str(const std::string& cmd) diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp index 50384b2a6..49494e889 100644 --- a/src/daemon/main.cpp +++ b/src/daemon/main.cpp @@ -138,6 +138,28 @@ int main(int argc, char const * argv[]) return 0; } + std::string config = command_line::get_arg(vm, daemon_args::arg_config_file); + boost::filesystem::path config_path(config); + boost::system::error_code ec; + if (bf::exists(config_path, ec)) + { + try + { + po::store(po::parse_config_file<char>(config_path.string<std::string>().c_str(), core_settings), vm); + } + catch (const std::exception &e) + { + // log system isn't initialized yet + std::cerr << "Error parsing config file: " << e.what() << std::endl; + throw; + } + } + else if (!command_line::is_arg_defaulted(vm, daemon_args::arg_config_file)) + { + std::cerr << "Can't find config file " << config << std::endl; + return 1; + } + const bool testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on); const bool stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on); if (testnet && stagenet) @@ -170,29 +192,6 @@ int main(int argc, char const * argv[]) //bf::path relative_path_base = daemonizer::get_relative_path_base(vm); bf::path relative_path_base = data_dir; - std::string config = command_line::get_arg(vm, daemon_args::arg_config_file); - - boost::filesystem::path data_dir_path(data_dir); - boost::filesystem::path config_path(config); - if (!config_path.has_parent_path()) - { - config_path = data_dir / config_path; - } - - boost::system::error_code ec; - if (bf::exists(config_path, ec)) - { - try - { - po::store(po::parse_config_file<char>(config_path.string<std::string>().c_str(), core_settings), vm); - } - catch (const std::exception &e) - { - // log system isn't initialized yet - std::cerr << "Error parsing config file: " << e.what() << std::endl; - throw; - } - } po::notify(vm); // log_file_path diff --git a/src/device/device.hpp b/src/device/device.hpp index b47460472..9df0cb39d 100644 --- a/src/device/device.hpp +++ b/src/device/device.hpp @@ -80,6 +80,9 @@ namespace hw { class device { + protected: + std::string name; + public: device() {} @@ -87,12 +90,12 @@ namespace hw { virtual ~device() {} explicit virtual operator bool() const = 0; - - static const int SIGNATURE_REAL = 0; - static const int SIGNATURE_FAKE = 1; - - - std::string name; + enum device_mode { + NONE, + TRANSACTION_CREATE_REAL, + TRANSACTION_CREATE_FAKE, + TRANSACTION_PARSE + }; /* ======================================================================= */ /* SETUP/TEARDOWN */ @@ -104,7 +107,18 @@ namespace hw { virtual bool release() = 0; virtual bool connect(void) = 0; - virtual bool disconnect() = 0; + virtual bool disconnect(void) = 0; + + virtual bool set_mode(device_mode mode) = 0; + + + /* ======================================================================= */ + /* LOCKER */ + /* ======================================================================= */ + virtual void lock(void) = 0; + virtual void unlock(void) = 0; + virtual bool try_lock(void) = 0; + /* ======================================================================= */ /* WALLET & ADDRESS */ @@ -131,6 +145,7 @@ namespace hw { virtual bool sc_secret_add( crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) = 0; virtual crypto::secret_key generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false) = 0; virtual bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) = 0; + virtual bool conceal_derivation(crypto::key_derivation &derivation, const crypto::public_key &tx_pub_key, const std::vector<crypto::public_key> &additional_tx_pub_keys, const crypto::key_derivation &main_derivation, const std::vector<crypto::key_derivation> &additional_derivations) = 0; virtual bool derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) = 0; virtual bool derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) = 0; virtual bool derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub) = 0; @@ -158,8 +173,6 @@ namespace hw { virtual bool open_tx(crypto::secret_key &tx_key) = 0; - virtual bool set_signature_mode(unsigned int sig_mode) = 0; - virtual bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) = 0; bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) { @@ -183,6 +196,12 @@ namespace hw { virtual bool close_tx(void) = 0; } ; + struct reset_mode { + device& hwref; + reset_mode(hw::device& dev) : hwref(dev) { } + ~reset_mode() { hwref.set_mode(hw::device::NONE);} + }; + device& get_device(const std::string device_descriptor) ; } diff --git a/src/device/device_default.cpp b/src/device/device_default.cpp index d63dafe9e..0071f7d4f 100644 --- a/src/device/device_default.cpp +++ b/src/device/device_default.cpp @@ -31,6 +31,7 @@ #include "device_default.hpp" +#include "common/int-util.h" #include "cryptonote_basic/account.h" #include "cryptonote_basic/subaddress_index.h" #include "ringct/rctOps.h" @@ -81,6 +82,20 @@ namespace hw { dfns(); } + bool device_default::set_mode(device_mode mode) { + return true; + } + + /* ======================================================================= */ + /* LOCKER */ + /* ======================================================================= */ + + void device_default::lock() { } + + bool device_default::try_lock() { return true; } + + void device_default::unlock() { } + /* ======================================================================= */ /* WALLET & ADDRESS */ /* ======================================================================= */ @@ -181,10 +196,13 @@ namespace hw { crypto::secret_key device_default::get_subaddress_secret_key(const crypto::secret_key &a, const cryptonote::subaddress_index &index) { const char prefix[] = "SubAddr"; - char data[sizeof(prefix) + sizeof(crypto::secret_key) + sizeof(cryptonote::subaddress_index)]; + char data[sizeof(prefix) + sizeof(crypto::secret_key) + 2 * sizeof(uint32_t)]; memcpy(data, prefix, sizeof(prefix)); memcpy(data + sizeof(prefix), &a, sizeof(crypto::secret_key)); - memcpy(data + sizeof(prefix) + sizeof(crypto::secret_key), &index, sizeof(cryptonote::subaddress_index)); + uint32_t idx = SWAP32LE(index.major); + memcpy(data + sizeof(prefix) + sizeof(crypto::secret_key), &idx, sizeof(uint32_t)); + idx = SWAP32LE(index.minor); + memcpy(data + sizeof(prefix) + sizeof(crypto::secret_key) + sizeof(uint32_t), &idx, sizeof(uint32_t)); crypto::secret_key m; crypto::hash_to_scalar(data, sizeof(data), m); return m; @@ -246,6 +264,10 @@ namespace hw { return true; } + bool device_default::conceal_derivation(crypto::key_derivation &derivation, const crypto::public_key &tx_pub_key, const std::vector<crypto::public_key> &additional_tx_pub_keys, const crypto::key_derivation &main_derivation, const std::vector<crypto::key_derivation> &additional_derivations){ + return true; + } + /* ======================================================================= */ /* TRANSACTION */ /* ======================================================================= */ @@ -262,10 +284,6 @@ namespace hw { return true; } - bool device_default::set_signature_mode(unsigned int sig_mode) { - return true; - } - bool device_default::encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) { crypto::key_derivation derivation; crypto::hash hash; diff --git a/src/device/device_default.hpp b/src/device/device_default.hpp index 02faeba0c..771fbba72 100644 --- a/src/device/device_default.hpp +++ b/src/device/device_default.hpp @@ -58,8 +58,17 @@ namespace hw { bool connect(void) override; bool disconnect() override; + + bool set_mode(device_mode mode) override; /* ======================================================================= */ + /* LOCKER */ + /* ======================================================================= */ + void lock(void) override; + void unlock(void) override; + bool try_lock(void) override; + + /* ======================================================================= */ /* WALLET & ADDRESS */ /* ======================================================================= */ bool get_public_address(cryptonote::account_public_address &pubkey) override; @@ -84,6 +93,7 @@ namespace hw { bool sc_secret_add(crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) override; crypto::secret_key generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false) override; bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) override; + bool conceal_derivation(crypto::key_derivation &derivation, const crypto::public_key &tx_pub_key, const std::vector<crypto::public_key> &additional_tx_pub_keys, const crypto::key_derivation &main_derivation, const std::vector<crypto::key_derivation> &additional_derivations) override; bool derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) override; bool derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) override; bool derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub) override; @@ -97,9 +107,6 @@ namespace hw { bool open_tx(crypto::secret_key &tx_key) override; - //bool get_additional_key(const bool subaddr, cryptonote::keypair &additional_txkey) override; - bool set_signature_mode(unsigned int sig_mode) override; - bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) override; bool ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & sharedSec) override; diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp index b3c0035a1..3b9ab6744 100644 --- a/src/device/device_ledger.cpp +++ b/src/device/device_ledger.cpp @@ -33,7 +33,8 @@ #include "cryptonote_basic/account.h" #include "cryptonote_basic/subaddress_index.h" - +#include <boost/thread/locks.hpp> +#include <boost/thread/lock_guard.hpp> namespace hw { @@ -55,10 +56,11 @@ namespace hw { #define ASSERT_RV(rv) CHECK_AND_ASSERT_THROW_MES((rv)==SCARD_S_SUCCESS, "Fail SCard API : (" << (rv) << ") "<< pcsc_stringify_error(rv)<<" Device="<<this->id<<", hCard="<<hCard<<", hContext="<<hContext); #define ASSERT_SW(sw,ok,msk) CHECK_AND_ASSERT_THROW_MES(((sw)&(mask))==(ok), "Wrong Device Status : SW=" << std::hex << (sw) << " (EXPECT=" << std::hex << (ok) << ", MASK=" << std::hex << (mask) << ")") ; #define ASSERT_T0(exp) CHECK_AND_ASSERT_THROW_MES(exp, "Protocol assert failure: "#exp ) ; + #define ASSERT_X(exp,msg) CHECK_AND_ASSERT_THROW_MES(exp, msg); #ifdef DEBUG_HWDEVICE - crypto::secret_key viewkey; - crypto::secret_key spendkey; + crypto::secret_key dbg_viewkey; + crypto::secret_key dbg_spendkey; #endif /* ===================================================================== */ @@ -118,7 +120,18 @@ namespace hw { #endif /* ===================================================================== */ - /* === Device ==== */ + /* === Internal Helpers ==== */ + /* ===================================================================== */ + static bool is_fake_view_key(const crypto::secret_key &sec) { + return sec == crypto::null_skey; + } + + bool operator==(const crypto::key_derivation &d0, const crypto::key_derivation &d1) { + return !memcmp(&d0, &d1, sizeof(d0)); + } + + /* ===================================================================== */ + /* === Device ==== */ /* ===================================================================== */ static int device_id = 0; @@ -196,6 +209,8 @@ namespace hw { this->hCard = 0; this->hContext = 0; this->reset_buffer(); + this->mode = NONE; + this->has_view_key = false; MDEBUG( "Device "<<this->id <<" Created"); } @@ -204,14 +219,51 @@ namespace hw { MDEBUG( "Device "<<this->id <<" Destroyed"); } + /* ======================================================================= */ + /* LOCKER */ + /* ======================================================================= */ + + //automatic lock one more level on device ensuring the current thread is allowed to use it + #define AUTO_LOCK_CMD() \ + /* lock both mutexes without deadlock*/ \ + boost::lock(device_locker, command_locker); \ + /* make sure both already-locked mutexes are unlocked at the end of scope */ \ + boost::lock_guard<boost::recursive_mutex> lock1(device_locker, boost::adopt_lock); \ + boost::lock_guard<boost::mutex> lock2(command_locker, boost::adopt_lock) + + //lock the device for a long sequence + void device_ledger::lock(void) { + MDEBUG( "Ask for LOCKING for device "<<this->name << " in thread "); + device_locker.lock(); + MDEBUG( "Device "<<this->name << " LOCKed"); + } + + //lock the device for a long sequence + bool device_ledger::try_lock(void) { + MDEBUG( "Ask for LOCKING(try) for device "<<this->name << " in thread "); + bool r = device_locker.try_lock(); + if (r) { + MDEBUG( "Device "<<this->name << " LOCKed(try)"); + } else { + MDEBUG( "Device "<<this->name << " not LOCKed(try)"); + } + return r; + } + + //lock the device for a long sequence + void device_ledger::unlock(void) { + try { + MDEBUG( "Ask for UNLOCKING for device "<<this->name << " in thread "); + } catch (...) { + } + device_locker.unlock(); + MDEBUG( "Device "<<this->name << " UNLOCKed"); + } /* ======================================================================= */ /* MISC */ /* ======================================================================= */ bool device_ledger::reset() { - - lock_device(); - try { int offset; reset_buffer(); @@ -227,12 +279,7 @@ namespace hw { this->buffer_send[4] = offset-5; this->length_send = offset; this->exchange(); - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return true; + return true; } unsigned int device_ledger::exchange(unsigned int ok, unsigned int mask) { @@ -261,30 +308,6 @@ namespace hw { memset(this->buffer_recv, 0, BUFFER_RECV_SIZE); } - void device_ledger::lock_device() { - MDEBUG( "Ask for LOCKING for device "<<this->id); - device_locker.lock(); - MDEBUG( "Device "<<this->id << " LOCKed"); - } - void device_ledger::unlock_device() { - try { - MDEBUG( "Ask for UNLOCKING for device "<<this->id); - } catch (...) { - } - device_locker.unlock(); - MDEBUG( "Device "<<this->id << " UNLOCKed"); - } - void device_ledger::lock_tx() { - MDEBUG( "Ask for LOCKING for TX "<<this->id); - //tx_locker.lock(); - MDEBUG( "TX "<<this->id << " LOCKed"); - } - void device_ledger::unlock_tx() { - MDEBUG( "Ask for UNLOCKING for TX "<<this->id); - //tx_locker.unlock(); - MDEBUG( "TX "<<this->id << " UNLOCKed"); - } - /* ======================================================================= */ /* SETUP/TEARDOWN */ /* ======================================================================= */ @@ -394,10 +417,10 @@ namespace hw { #ifdef DEBUG_HWDEVICE cryptonote::account_public_address pubkey; this->get_public_address(pubkey); + #endif crypto::secret_key vkey; crypto::secret_key skey; this->get_secret_keys(vkey,skey); - #endif return rv==SCARD_S_SUCCESS; } @@ -411,16 +434,55 @@ namespace hw { return true; } + bool device_ledger::set_mode(device_mode mode) { + AUTO_LOCK_CMD(); + + int offset; + + reset_buffer(); + + switch(mode) { + case TRANSACTION_CREATE_REAL: + case TRANSACTION_CREATE_FAKE: + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_SET_SIGNATURE_MODE; + this->buffer_send[2] = 0x01; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + //account + this->buffer_send[offset] = mode; + offset += 1; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + this->mode = mode; + break; + + case TRANSACTION_PARSE: + case NONE: + this->mode = mode; + break; + default: + CHECK_AND_ASSERT_THROW_MES(false, " device_ledger::set_mode(unsigned int mode): invalid mode: "<<mode); + } + MDEBUG("Switch to mode: " <<mode); + return true; + } + /* ======================================================================= */ /* WALLET & ADDRESS */ /* ======================================================================= */ - /* Application API */ bool device_ledger::get_public_address(cryptonote::account_public_address &pubkey){ + AUTO_LOCK_CMD(); - lock_device(); - try { int offset; reset_buffer(); @@ -440,21 +502,17 @@ namespace hw { memmove(pubkey.m_view_public_key.data, this->buffer_recv, 32); memmove(pubkey.m_spend_public_key.data, this->buffer_recv+32, 32); - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return true; + + return true; } - bool device_ledger::get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) { - memset(viewkey.data, 0x00, 32); - memset(spendkey.data, 0xFF, 32); + bool device_ledger::get_secret_keys(crypto::secret_key &vkey , crypto::secret_key &skey) { + AUTO_LOCK_CMD(); + + //secret key are represented as fake key on the wallet side + memset(vkey.data, 0x00, 32); + memset(skey.data, 0xFF, 32); - #ifdef DEBUG_HWDEVICE - lock_device(); - try { //spcialkey, normal conf handled in decrypt int offset; reset_buffer(); @@ -473,21 +531,26 @@ namespace hw { this->length_send = offset; this->exchange(); - //clear key - memmove(ledger::viewkey.data, this->buffer_recv+64, 32); - memmove(ledger::spendkey.data, this->buffer_recv+96, 32); - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - #endif - return true; + //View key is retrievied, if allowed, to speed up blockchain parsing + memmove(this->viewkey.data, this->buffer_recv+0, 32); + if (is_fake_view_key(this->viewkey)) { + MDEBUG("Have Not view key"); + this->has_view_key = false; + } else { + MDEBUG("Have view key"); + this->has_view_key = true; + } + + #ifdef DEBUG_HWDEVICE + memmove(dbg_viewkey.data, this->buffer_recv+0, 32); + memmove(dbg_spendkey.data, this->buffer_recv+32, 32); + #endif + + return true; } bool device_ledger::generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) { - lock_device(); - try { + AUTO_LOCK_CMD(); int offset; #ifdef DEBUG_HWDEVICE @@ -519,11 +582,6 @@ namespace hw { hw::ledger::check32("generate_chacha_key_prehashed", "key", (char*)key_x.data(), (char*)key.data()); #endif - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } return true; } @@ -532,15 +590,15 @@ namespace hw { /* ======================================================================= */ bool device_ledger::derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, const std::size_t output_index, crypto::public_key &derived_pub){ - - lock_device(); - try { - int offset =0; - unsigned char options = 0; - + AUTO_LOCK_CMD(); #ifdef DEBUG_HWDEVICE const crypto::public_key pub_x = pub; - const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation); + crypto::key_derivation derivation_x; + if ((this->mode == TRANSACTION_PARSE) && has_view_key) { + derivation_x = derivation; + } else { + derivation_x = hw::ledger::decrypt(derivation); + } const std::size_t output_index_x = output_index; crypto::public_key derived_pub_x; hw::ledger::log_hexbuffer("derive_subaddress_public_key: [[IN]] pub ", pub_x.data, 32); @@ -550,10 +608,17 @@ namespace hw { hw::ledger::log_hexbuffer("derive_subaddress_public_key: [[OUT]] derived_pub", derived_pub_x.data, 32); #endif + if ((this->mode == TRANSACTION_PARSE) && has_view_key) { + //If we are in TRANSACTION_PARSE, the given derivation has been retrieved uncrypted (wihtout the help + //of the device), so continue that way. + MDEBUG( "derive_subaddress_public_key : PARSE mode with known viewkey"); + crypto::derive_subaddress_public_key(pub, derivation, output_index,derived_pub); + } else { + + int offset =0; + reset_buffer(); - options = 0; - this->buffer_send[0] = 0x00; this->buffer_send[1] = INS_DERIVE_SUBADDRESS_PUBLIC_KEY; this->buffer_send[2] = 0x00; @@ -561,7 +626,7 @@ namespace hw { this->buffer_send[4] = 0x00; offset = 5; //options - this->buffer_send[offset] = options; + this->buffer_send[offset] = 0; offset += 1; //pub memmove(this->buffer_send+offset, pub.data, 32); @@ -582,34 +647,27 @@ namespace hw { //pub key memmove(derived_pub.data, &this->buffer_recv[0], 32); - - #ifdef DEBUG_HWDEVICE - hw::ledger::check32("derive_subaddress_public_key", "derived_pub", derived_pub_x.data, derived_pub.data); - #endif - - unlock_device(); - }catch (...) { - unlock_device(); - throw; } + #ifdef DEBUG_HWDEVICE + hw::ledger::check32("derive_subaddress_public_key", "derived_pub", derived_pub_x.data, derived_pub.data); + #endif + return true; } crypto::public_key device_ledger::get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) { - crypto::public_key D; - lock_device(); - try { - int offset =0; - unsigned char options = 0; + AUTO_LOCK_CMD(); + crypto::public_key D; + int offset; #ifdef DEBUG_HWDEVICE const cryptonote::account_keys keys_x = hw::ledger::decrypt(keys); const cryptonote::subaddress_index index_x = index; crypto::public_key D_x; - hw::ledger::log_hexbuffer("derive_subaddress_public_key: [[IN]] keys.m_view_secret_key ", keys_x.m_view_secret_key.data,32); - hw::ledger::log_hexbuffer("derive_subaddress_public_key: [[IN]] keys.m_spend_secret_key", keys_x.m_spend_secret_key.data,32); + hw::ledger::log_hexbuffer("get_subaddress_spend_public_key: [[IN]] keys.m_view_secret_key ", keys_x.m_view_secret_key.data,32); + hw::ledger::log_hexbuffer("get_subaddress_spend_public_key: [[IN]] keys.m_spend_secret_key", keys_x.m_spend_secret_key.data,32); hw::ledger::log_message ("get_subaddress_spend_public_key: [[IN]] index ", std::to_string(index_x.major)+"."+std::to_string(index_x.minor)); - this->controle_device->get_subaddress_spend_public_key(keys_x, index_x, D_x); + D_x = this->controle_device->get_subaddress_spend_public_key(keys_x, index_x); hw::ledger::log_hexbuffer("get_subaddress_spend_public_key: [[OUT]] derivation ", D_x.data, 32); #endif @@ -644,12 +702,7 @@ namespace hw { hw::ledger::check32("get_subaddress_spend_public_key", "D", D_x.data, D.data); #endif - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return D; + return D; } std::vector<crypto::public_key> device_ledger::get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end) { @@ -665,24 +718,22 @@ namespace hw { } cryptonote::account_public_address device_ledger::get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) { - cryptonote::account_public_address address; - lock_device(); - try { - int offset =0; - unsigned char options = 0; + AUTO_LOCK_CMD(); + cryptonote::account_public_address address; + int offset; #ifdef DEBUG_HWDEVICE const cryptonote::account_keys keys_x = hw::ledger::decrypt(keys); const cryptonote::subaddress_index index_x = index; cryptonote::account_public_address address_x; - hw::ledger::log_hexbuffer("derive_subaddress_public_key: [[IN]] keys.m_view_secret_key ", keys_x.m_view_secret_key.data, 32); - hw::ledger::log_hexbuffer("derive_subaddress_public_key: [[IN]] keys.m_view_public_key", keys_x.m_account_address.m_view_public_key.data, 32); - hw::ledger::log_hexbuffer("derive_subaddress_public_key: [[IN]] keys.m_view_secret_key ", keys_x.m_view_secret_key.data, 32); - hw::ledger::log_hexbuffer("derive_subaddress_public_key: [[IN]] keys.m_spend_public_key", keys_x.m_account_address.m_spend_public_key.data, 32); + hw::ledger::log_hexbuffer("get_subaddress: [[IN]] keys.m_view_secret_key ", keys_x.m_view_secret_key.data, 32); + hw::ledger::log_hexbuffer("get_subaddress: [[IN]] keys.m_view_public_key", keys_x.m_account_address.m_view_public_key.data, 32); + hw::ledger::log_hexbuffer("get_subaddress: [[IN]] keys.m_view_secret_key ", keys_x.m_view_secret_key.data, 32); + hw::ledger::log_hexbuffer("get_subaddress: [[IN]] keys.m_spend_public_key", keys_x.m_account_address.m_spend_public_key.data, 32); hw::ledger::log_message ("get_subaddress: [[IN]] index ", std::to_string(index_x.major)+"."+std::to_string(index_x.minor)); - this->controle_device->get_subaddress(keys_x, index_x, address_x); - hw::ledger::log_hexbuffer("derive_subaddress_public_key: [[IN]] keys.m_view_public_key ", address_x.m_view_public_key.data, 32); - hw::ledger::log_hexbuffer("derive_subaddress_public_key: [[IN]] keys.m_spend_public_key", address_x.m_spend_public_key.data, 32); + address_x = this->controle_device->get_subaddress(keys_x, index_x); + hw::ledger::log_hexbuffer("get_subaddress: [[OUT]] keys.m_view_public_key ", address_x.m_view_public_key.data, 32); + hw::ledger::log_hexbuffer("get_subaddress: [[OUT]] keys.m_spend_public_key", address_x.m_spend_public_key.data, 32); #endif if (index.is_zero()) { @@ -717,20 +768,13 @@ namespace hw { hw::ledger::check32("get_subaddress", "address.m_spend_public_key.data", address_x.m_spend_public_key.data, address.m_spend_public_key.data); #endif - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return address; + return address; } crypto::secret_key device_ledger::get_subaddress_secret_key(const crypto::secret_key &sec, const cryptonote::subaddress_index &index) { - crypto::secret_key sub_sec; - lock_device(); - try { - int offset =0; - unsigned char options = 0; + AUTO_LOCK_CMD(); + crypto::secret_key sub_sec; + int offset; #ifdef DEBUG_HWDEVICE const crypto::secret_key sec_x = hw::ledger::decrypt(sec); @@ -738,7 +782,7 @@ namespace hw { crypto::secret_key sub_sec_x; hw::ledger::log_message ("get_subaddress_secret_key: [[IN]] index ", std::to_string(index.major)+"."+std::to_string(index.minor)); hw::ledger::log_hexbuffer("get_subaddress_secret_key: [[IN]] sec ", sec_x.data, 32); - this->controle_device->get_subaddress_secret_key(sec_x, index_x, sub_sec_x); + sub_sec_x = this->controle_device->get_subaddress_secret_key(sec_x, index_x); hw::ledger::log_hexbuffer("get_subaddress_secret_key: [[OUT]] sub_sec", sub_sec_x.data, 32); #endif @@ -751,7 +795,7 @@ namespace hw { this->buffer_send[4] = 0x00; offset = 5; //options - this->buffer_send[offset] = options; + this->buffer_send[offset] = 0; offset += 1; //sec memmove(this->buffer_send+offset, sec.data, 32); @@ -772,12 +816,7 @@ namespace hw { hw::ledger::check32("get_subaddress_secret_key", "sub_sec", sub_sec_x.data, sub_sec_clear.data); #endif - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return sub_sec; + return sub_sec; } /* ======================================================================= */ @@ -785,10 +824,9 @@ namespace hw { /* ======================================================================= */ bool device_ledger::verify_keys(const crypto::secret_key &secret_key, const crypto::public_key &public_key) { - lock_device(); - try { - int offset =0,sw; - unsigned char options = 0; + AUTO_LOCK_CMD(); + int offset, sw; + reset_buffer(); this->buffer_send[0] = 0x00; this->buffer_send[1] = INS_VERIFY_KEY; @@ -816,20 +854,12 @@ namespace hw { this->buffer_recv[2] << 8 | this->buffer_recv[3] << 0 ; - unlock_device(); return verified == 1; - }catch (...) { - unlock_device(); - throw; - } - return false; } bool device_ledger::scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) { - lock_device(); - try { - int offset =0; - unsigned char options = 0; + AUTO_LOCK_CMD(); + int offset; #ifdef DEBUG_HWDEVICE const rct::key P_x = P; @@ -843,8 +873,6 @@ namespace hw { reset_buffer(); - options = 0; - this->buffer_send[0] = 0x00; this->buffer_send[1] = INS_SECRET_SCAL_MUL_KEY; this->buffer_send[2] = 0x00; @@ -852,7 +880,7 @@ namespace hw { this->buffer_send[4] = 0x00; offset = 5; //options - this->buffer_send[offset] = options; + this->buffer_send[offset] = 0; offset += 1; //pub memmove(this->buffer_send+offset, P.bytes, 32); @@ -873,19 +901,12 @@ namespace hw { hw::ledger::check32("scalarmultKey", "mulkey", (char*)aP_x.bytes, (char*)aP.bytes); #endif - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return true; + return true; } bool device_ledger::scalarmultBase(rct::key &aG, const rct::key &a) { - lock_device(); - try { - int offset =0; - unsigned char options = 0; + AUTO_LOCK_CMD(); + int offset; #ifdef DEBUG_HWDEVICE const rct::key a_x = hw::ledger::decrypt(a); @@ -897,8 +918,6 @@ namespace hw { reset_buffer(); - options = 0; - this->buffer_send[0] = 0x00; this->buffer_send[1] = INS_SECRET_SCAL_MUL_BASE; this->buffer_send[2] = 0x00; @@ -906,7 +925,7 @@ namespace hw { this->buffer_send[4] = 0x00; offset = 5; //options - this->buffer_send[offset] = options; + this->buffer_send[offset] = 0; offset += 1; //sec memmove(this->buffer_send+offset, a.bytes, 32); @@ -923,20 +942,12 @@ namespace hw { hw::ledger::check32("scalarmultBase", "mulkey", (char*)aG_x.bytes, (char*)aG.bytes); #endif - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return true; + return true; } bool device_ledger::sc_secret_add( crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) { - - lock_device(); - try { - int offset =0; - unsigned char options = 0; + AUTO_LOCK_CMD(); + int offset; #ifdef DEBUG_HWDEVICE const crypto::secret_key a_x = hw::ledger::decrypt(a); @@ -947,8 +958,6 @@ namespace hw { reset_buffer(); - options = 0; - this->buffer_send[0] = 0x00; this->buffer_send[1] = INS_SECRET_KEY_ADD; this->buffer_send[2] = 0x00; @@ -956,7 +965,7 @@ namespace hw { this->buffer_send[4] = 0x00; offset = 5; //options - this->buffer_send[offset] = options; + this->buffer_send[offset] = 0; offset += 1; //sec key memmove(this->buffer_send+offset, a.data, 32); @@ -977,23 +986,16 @@ namespace hw { hw::ledger::check32("sc_secret_add", "r", r_x.data, r_clear.data); #endif - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return true; + return true; } crypto::secret_key device_ledger::generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key, bool recover) { - if (recover) { - throw std::runtime_error("device generate key does not support recover"); - } + AUTO_LOCK_CMD(); + if (recover) { + throw std::runtime_error("device generate key does not support recover"); + } - lock_device(); - try { - int offset =0; - unsigned char options = 0; + int offset; #ifdef DEBUG_HWDEVICE bool recover_x = recover; @@ -1004,8 +1006,6 @@ namespace hw { reset_buffer(); - options = 0; - this->buffer_send[0] = 0x00; this->buffer_send[1] = INS_GENERATE_KEYPAIR; this->buffer_send[2] = 0x00; @@ -1013,7 +1013,7 @@ namespace hw { this->buffer_send[4] = 0x00; offset = 5; //options - this->buffer_send[offset] = options; + this->buffer_send[offset] = 0; offset += 1; this->buffer_send[4] = offset-5; @@ -1031,20 +1031,13 @@ namespace hw { hw::ledger::check32("generate_keys", "pub", pub_x.data, pub.data); #endif - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return sec; + return sec; } bool device_ledger::generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) { - lock_device(); - try { - int offset =0; - unsigned char options = 0; + AUTO_LOCK_CMD(); + bool r = false; #ifdef DEBUG_HWDEVICE const crypto::public_key pub_x = pub; @@ -1056,6 +1049,17 @@ namespace hw { hw::ledger::log_hexbuffer("generate_key_derivation: [[OUT]] derivation", derivation_x.data, 32); #endif + if ((this->mode == TRANSACTION_PARSE) && has_view_key) { + //A derivation is resquested in PASRE mode and we have the view key, + //so do that wihtout the device and return the derivation unencrypted. + MDEBUG( "generate_key_derivation : PARSE mode with known viewkey"); + //Note derivation in PARSE mode can only happen with viewkey, so assert it! + assert(is_fake_view_key(sec)); + r = crypto::generate_key_derivation(pub, this->viewkey, derivation); + } else { + + int offset; + reset_buffer(); this->buffer_send[0] = 0x00; @@ -1065,7 +1069,7 @@ namespace hw { this->buffer_send[4] = 0x00; offset = 5; //options - this->buffer_send[offset] = options; + this->buffer_send[offset] = 0; offset += 1; //pub memmove(this->buffer_send+offset, pub.data, 32); @@ -1080,25 +1084,42 @@ namespace hw { //derivattion data memmove(derivation.data, &this->buffer_recv[0], 32); + r = true; + } + #ifdef DEBUG_HWDEVICE + crypto::key_derivation derivation_clear ; + if ((this->mode == TRANSACTION_PARSE) && has_view_key) { + derivation_clear = derivation; + }else { + derivation_clear = hw::ledger::decrypt(derivation); + } + hw::ledger::check32("generate_key_derivation", "derivation", derivation_x.data, derivation_clear.data); + #endif - #ifdef DEBUG_HWDEVICE - crypto::key_derivation derivation_clear = hw::ledger::decrypt(derivation); - hw::ledger::check32("generate_key_derivation", "derivation", derivation_x.data, derivation_clear.data); - #endif + return r; + } - unlock_device(); - }catch (...) { - unlock_device(); - throw; + bool device_ledger::conceal_derivation(crypto::key_derivation &derivation, const crypto::public_key &tx_pub_key, const std::vector<crypto::public_key> &additional_tx_pub_keys, const crypto::key_derivation &main_derivation, const std::vector<crypto::key_derivation> &additional_derivations) { + const crypto::public_key *pkey=NULL; + if (derivation == main_derivation) { + pkey = &tx_pub_key; + MDEBUG("conceal derivation with main tx pub key"); + } else { + for(size_t n=0; n < additional_derivations.size();++n) { + if(derivation == additional_derivations[n]) { + pkey = &additional_tx_pub_keys[n]; + MDEBUG("conceal derivation with additionnal tx pub key"); + break; + } + } } - return true; - } + ASSERT_X(pkey, "Mismatched derivation on scan info"); + return this->generate_key_derivation(*pkey, crypto::null_skey, derivation); + } bool device_ledger::derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) { - lock_device(); - try { + AUTO_LOCK_CMD(); int offset; - unsigned char options; #ifdef DEBUG_HWDEVICE const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation); @@ -1112,8 +1133,6 @@ namespace hw { reset_buffer(); - options = 0; - this->buffer_send[0] = 0x00; this->buffer_send[1] = INS_DERIVATION_TO_SCALAR; this->buffer_send[2] = 0x00; @@ -1121,7 +1140,7 @@ namespace hw { this->buffer_send[4] = 0x00; offset = 5; //options - this->buffer_send[offset] = options; + this->buffer_send[offset] = 0; offset += 1; //derivattion memmove(this->buffer_send+offset, derivation.data, 32); @@ -1145,19 +1164,12 @@ namespace hw { hw::ledger::check32("derivation_to_scalar", "res", res_x.data, res_clear.data); #endif - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return true; + return true; } bool device_ledger::derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) { - lock_device(); - try { + AUTO_LOCK_CMD(); int offset; - unsigned char options; #ifdef DEBUG_HWDEVICE const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation); @@ -1173,8 +1185,6 @@ namespace hw { reset_buffer(); - options = 0; - this->buffer_send[0] = 0x00; this->buffer_send[1] = INS_DERIVE_SECRET_KEY; this->buffer_send[2] = 0x00; @@ -1182,7 +1192,7 @@ namespace hw { this->buffer_send[4] = 0x00; offset = 5; //options - this->buffer_send[offset] = options; + this->buffer_send[offset] = 0; offset += 1; //derivation memmove(this->buffer_send+offset, derivation.data, 32); @@ -1209,20 +1219,13 @@ namespace hw { hw::ledger::check32("derive_secret_key", "derived_sec", derived_sec_x.data, derived_sec_clear.data); #endif - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return true; + return true; } bool device_ledger::derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub){ - lock_device(); - try { + AUTO_LOCK_CMD(); int offset; - unsigned char options; - + #ifdef DEBUG_HWDEVICE const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation); const std::size_t output_index_x = output_index; @@ -1237,8 +1240,6 @@ namespace hw { reset_buffer(); - options = 0; - this->buffer_send[0] = 0x00; this->buffer_send[1] = INS_DERIVE_PUBLIC_KEY; this->buffer_send[2] = 0x00; @@ -1246,7 +1247,7 @@ namespace hw { this->buffer_send[4] = 0x00; offset = 5; //options - this->buffer_send[offset] = options; + this->buffer_send[offset] = 0; offset += 1; //derivation memmove(this->buffer_send+offset, derivation.data, 32); @@ -1272,19 +1273,12 @@ namespace hw { hw::ledger::check32("derive_public_key", "derived_pub", derived_pub_x.data, derived_pub.data); #endif - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return true; + return true; } bool device_ledger::secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) { - lock_device(); - try { + AUTO_LOCK_CMD(); int offset; - unsigned char options; #ifdef DEBUG_HWDEVICE const crypto::secret_key sec_x = hw::ledger::decrypt(sec); @@ -1299,8 +1293,6 @@ namespace hw { reset_buffer(); - options = 0; - this->buffer_send[0] = 0x00; this->buffer_send[1] = INS_SECRET_KEY_TO_PUBLIC_KEY; this->buffer_send[2] = 0x00; @@ -1308,7 +1300,7 @@ namespace hw { this->buffer_send[4] = 0x00; offset = 5; //options - this->buffer_send[offset] = options; + this->buffer_send[offset] = 0; offset += 1; //sec key memmove(this->buffer_send+offset, sec.data, 32); @@ -1325,19 +1317,12 @@ namespace hw { hw::ledger::check32("secret_key_to_public_key", "pub", pub_x.data, pub.data); #endif - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return true; + return true; } bool device_ledger::generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image){ - lock_device(); - try { + AUTO_LOCK_CMD(); int offset; - unsigned char options; #ifdef DEBUG_HWDEVICE const crypto::public_key pub_x = pub; @@ -1351,8 +1336,6 @@ namespace hw { reset_buffer(); - options = 0; - this->buffer_send[0] = 0x00; this->buffer_send[1] = INS_GEN_KEY_IMAGE; this->buffer_send[2] = 0x00; @@ -1360,7 +1343,7 @@ namespace hw { this->buffer_send[4] = 0x00; offset = 5; //options - this->buffer_send[offset] = options; + this->buffer_send[offset] = 0; offset += 1; //pub memmove(this->buffer_send+offset, pub.data, 32); @@ -1380,12 +1363,7 @@ namespace hw { hw::ledger::check32("generate_key_image", "image", image_x.data, image.data); #endif - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return true; + return true; } /* ======================================================================= */ @@ -1393,12 +1371,9 @@ namespace hw { /* ======================================================================= */ bool device_ledger::open_tx(crypto::secret_key &tx_key) { - lock_device(); - try { - int offset =0; - unsigned char options = 0; + AUTO_LOCK_CMD(); + int offset; - lock_tx(); reset_buffer(); key_map.clear(); @@ -1423,57 +1398,19 @@ namespace hw { this->exchange(); memmove(tx_key.data, &this->buffer_recv[32], 32); - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return true; - } - - bool device_ledger::set_signature_mode(unsigned int sig_mode) { - lock_device(); - try { - int offset =0; - unsigned char options = 0; - - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_SET_SIGNATURE_MODE; - this->buffer_send[2] = 0x01; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0x00; - offset += 1; - //account - this->buffer_send[offset] = sig_mode; - offset += 1; - - this->buffer_send[4] = offset-5; - this->length_send = offset; - this->exchange(); - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return true; + + return true; } bool device_ledger::encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) { - lock_device(); - try { - int offset =0; - unsigned char options = 0; + AUTO_LOCK_CMD(); + int offset; #ifdef DEBUG_HWDEVICE const crypto::public_key public_key_x = public_key; const crypto::secret_key secret_key_x = hw::ledger::decrypt(secret_key); crypto::hash8 payment_id_x = payment_id; - this->controle_device->encrypt_payment_id(public_key_x, secret_key_x, payment_id_x); + this->controle_device->encrypt_payment_id(payment_id_x, public_key_x, secret_key_x); #endif reset_buffer(); @@ -1506,32 +1443,19 @@ namespace hw { hw::ledger::check8("stealth", "payment_id", payment_id_x.data, payment_id.data); #endif - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return true; + return true; } bool device_ledger::add_output_key_mapping(const crypto::public_key &Aout, const crypto::public_key &Bout, const bool is_subaddress, const size_t real_output_index, const rct::key &amount_key, const crypto::public_key &out_eph_public_key) { - lock_device(); - try { + AUTO_LOCK_CMD(); key_map.add(ABPkeys(rct::pk2rct(Aout),rct::pk2rct(Bout), is_subaddress, real_output_index, rct::pk2rct(out_eph_public_key), amount_key)); - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return true; + return true; } bool device_ledger::ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & AKout) { - lock_device(); - try { - int offset =0; - unsigned char options = 0; + AUTO_LOCK_CMD(); + int offset; #ifdef DEBUG_HWDEVICE const rct::key AKout_x = hw::ledger::decrypt(AKout); @@ -1574,19 +1498,12 @@ namespace hw { hw::ledger::log_hexbuffer("Blind AKV input", (char*)&this->buffer_recv[64], 3*32); #endif - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return true; + return true; } bool device_ledger::ecdhDecode(rct::ecdhTuple & masked, const rct::key & AKout) { - lock_device(); - try { - int offset =0; - unsigned char options = 0; + AUTO_LOCK_CMD(); + int offset; #ifdef DEBUG_HWDEVICE const rct::key AKout_x = hw::ledger::decrypt(AKout); @@ -1627,21 +1544,13 @@ namespace hw { hw::ledger::check32("ecdhDecode", "mask", (char*)masked_x.mask.bytes,(char*) masked.mask.bytes); #endif - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return true; + return true; } bool device_ledger::mlsag_prehash(const std::string &blob, size_t inputs_size, size_t outputs_size, const rct::keyV &hashes, const rct::ctkeyV &outPk, rct::key &prehash) { - - lock_device(); - try { - unsigned char options = 0; + AUTO_LOCK_CMD(); unsigned int data_offset, C_offset, kv_offset, i; const char *data; @@ -1834,21 +1743,15 @@ namespace hw { hw::ledger::check32("mlsag_prehash", "prehash", (char*)prehash_x.bytes, (char*)prehash.bytes); #endif - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return true; + return true; } bool device_ledger::mlsag_prepare(const rct::key &H, const rct::key &xx, rct::key &a, rct::key &aG, rct::key &aHP, rct::key &II) { - lock_device(); - try { - int offset =0; - unsigned char options = 0; + AUTO_LOCK_CMD(); + int offset; + unsigned char options; #ifdef DEBUG_HWDEVICE const rct::key H_x = H; @@ -1897,19 +1800,13 @@ namespace hw { hw::ledger::check32("mlsag_prepare", "II", (char*)II_x.bytes, (char*)II.bytes); #endif - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return true; + return true; } bool device_ledger::mlsag_prepare(rct::key &a, rct::key &aG) { - lock_device(); - try { - int offset =0; - unsigned char options = 0; + AUTO_LOCK_CMD(); + int offset; + unsigned char options; #ifdef DEBUG_HWDEVICE rct::key a_x; @@ -1941,19 +1838,13 @@ namespace hw { hw::ledger::check32("mlsag_prepare", "AG", (char*)aG_x.bytes, (char*)aG.bytes); #endif - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return true; + return true; } bool device_ledger::mlsag_hash(const rct::keyV &long_message, rct::key &c) { - lock_device(); - try { - int offset =0; - unsigned char options = 0; + AUTO_LOCK_CMD(); + int offset; + unsigned char options; size_t cnt; #ifdef DEBUG_HWDEVICE @@ -1991,20 +1882,12 @@ namespace hw { hw::ledger::check32("mlsag_hash", "c", (char*)c_x.bytes, (char*)c.bytes); #endif - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return true; - + return true; } bool device_ledger::mlsag_sign(const rct::key &c, const rct::keyV &xx, const rct::keyV &alpha, const size_t rows, const size_t dsRows, rct::keyV &ss) { - lock_device(); - try { - int offset =0; - unsigned char options = 0; + AUTO_LOCK_CMD(); + int offset; CHECK_AND_ASSERT_THROW_MES(dsRows<=rows, "dsRows greater than rows"); CHECK_AND_ASSERT_THROW_MES(xx.size() == rows, "xx size does not match rows"); @@ -2061,19 +1944,12 @@ namespace hw { } #endif - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return true; + return true; } bool device_ledger::close_tx() { - lock_device(); - try { - int offset =0; - unsigned char options = 0; + AUTO_LOCK_CMD(); + int offset; reset_buffer(); @@ -2091,13 +1967,7 @@ namespace hw { this->length_send = offset; this->exchange(); - unlock_tx(); - unlock_device(); - }catch (...) { - unlock_device(); - throw; - } - return true; + return true; } /* ---------------------------------------------------------- */ diff --git a/src/device/device_ledger.hpp b/src/device/device_ledger.hpp index e06c5f72c..f1fcaab87 100644 --- a/src/device/device_ledger.hpp +++ b/src/device/device_ledger.hpp @@ -32,11 +32,11 @@ #include <cstddef> #include <string> -#include <mutex> #include "device.hpp" #include <PCSC/winscard.h> #include <PCSC/wintypes.h> - +#include <boost/thread/mutex.hpp> +#include <boost/thread/recursive_mutex.hpp> namespace hw { @@ -80,13 +80,11 @@ namespace hw { class device_ledger : public hw::device { private: - mutable std::mutex device_locker; - mutable std::mutex tx_locker; - void lock_device() ; - void unlock_device() ; - void lock_tx() ; - void unlock_tx() ; - + // Locker for concurrent access + mutable boost::recursive_mutex device_locker; + mutable boost::mutex command_locker; + + //PCSC management std::string full_name; SCARDCONTEXT hContext; SCARDHANDLE hCard; @@ -95,15 +93,21 @@ namespace hw { DWORD length_recv; BYTE buffer_recv[BUFFER_RECV_SIZE]; unsigned int id; - - Keymap key_map; - - void logCMD(void); void logRESP(void); unsigned int exchange(unsigned int ok=0x9000, unsigned int mask=0xFFFF); void reset_buffer(void); + // hw running mode + device_mode mode; + // map public destination key to ephemeral destination key + Keymap key_map; + + // To speed up blockchain parsing the view key maybe handle here. + crypto::secret_key viewkey; + bool has_view_key; + + //extra debug #ifdef DEBUG_HWDEVICE device *controle_device; #endif @@ -130,6 +134,15 @@ namespace hw { bool connect(void) override; bool disconnect() override; + bool set_mode(device_mode mode) override; + + /* ======================================================================= */ + /* LOCKER */ + /* ======================================================================= */ + void lock(void) override; + void unlock(void) override; + bool try_lock(void) override; + /* ======================================================================= */ /* WALLET & ADDRESS */ /* ======================================================================= */ @@ -156,6 +169,7 @@ namespace hw { bool sc_secret_add(crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) override; crypto::secret_key generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false) override; bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) override; + bool conceal_derivation(crypto::key_derivation &derivation, const crypto::public_key &tx_pub_key, const std::vector<crypto::public_key> &additional_tx_pub_keys, const crypto::key_derivation &main_derivation, const std::vector<crypto::key_derivation> &additional_derivations) override; bool derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) override; bool derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) override; bool derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub) override; @@ -168,8 +182,6 @@ namespace hw { bool open_tx(crypto::secret_key &tx_key) override; - bool set_signature_mode(unsigned int sig_mode) override; - bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) override; bool ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & sharedSec) override; @@ -190,10 +202,9 @@ namespace hw { }; - #ifdef DEBUG_HWDEVICE - extern crypto::secret_key viewkey; - extern crypto::secret_key spendkey; + extern crypto::secret_key dbg_viewkey; + extern crypto::secret_key dbg_spendkey; #endif #endif //WITH_DEVICE_LEDGER diff --git a/src/device/log.cpp b/src/device/log.cpp index a2ad0f4f4..cbbcfc953 100644 --- a/src/device/log.cpp +++ b/src/device/log.cpp @@ -56,8 +56,8 @@ namespace hw { } #ifdef DEBUG_HWDEVICE - extern crypto::secret_key viewkey; - extern crypto::secret_key spendkey; + extern crypto::secret_key dbg_viewkey; + extern crypto::secret_key dbg_spendkey; void decrypt(char* buf, size_t len) { @@ -69,7 +69,7 @@ namespace hw { if (buf[i] != 0) break; } if (i == 32) { - memmove(buf, hw::ledger::viewkey.data, 32); + memmove(buf, hw::ledger::dbg_viewkey.data, 32); return; } //spend key? @@ -77,7 +77,7 @@ namespace hw { if (buf[i] != (char)0xff) break; } if (i == 32) { - memmove(buf, hw::ledger::spendkey.data, 32); + memmove(buf, hw::ledger::dbg_spendkey.data, 32); return; } } @@ -161,4 +161,4 @@ namespace hw { } #endif //WITH_DEVICE_LEDGER -}
\ No newline at end of file +} diff --git a/src/p2p/net_node.cpp b/src/p2p/net_node.cpp index bde6fc88e..c9ca63f43 100644 --- a/src/p2p/net_node.cpp +++ b/src/p2p/net_node.cpp @@ -39,7 +39,7 @@ namespace nodetool , "Port for p2p network protocol" , std::to_string(config::P2P_DEFAULT_PORT) , {{ &cryptonote::arg_testnet_on, &cryptonote::arg_stagenet_on }} - , [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val) { + , [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val)->std::string { if (testnet_stagenet[0] && defaulted) return std::to_string(config::testnet::P2P_DEFAULT_PORT); else if (testnet_stagenet[1] && defaulted) diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 54875e619..3b0d1c394 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -397,8 +397,8 @@ namespace nodetool full_addrs.insert("163.172.182.165:18080"); full_addrs.insert("161.67.132.39:18080"); full_addrs.insert("198.74.231.92:18080"); - full_addrs.insert("195.154.123.123:28080"); - full_addrs.insert("212.83.172.165:28080"); + full_addrs.insert("195.154.123.123:18080"); + full_addrs.insert("212.83.172.165:18080"); } return full_addrs; } @@ -490,7 +490,7 @@ namespace nodetool if (result.size()) { for (const auto& addr_string : result) - full_addrs.insert(addr_string + ":18080"); + full_addrs.insert(addr_string + ":" + std::to_string(m_nettype == cryptonote::TESTNET ? ::config::testnet::P2P_DEFAULT_PORT : m_nettype == cryptonote::STAGENET ? ::config::stagenet::P2P_DEFAULT_PORT : ::config::P2P_DEFAULT_PORT)); } ++i; } diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index c3d1a9d11..aa5728fc3 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -209,6 +209,15 @@ namespace cryptonote return true; } //------------------------------------------------------------------------------------------------------------------------------ + static cryptonote::blobdata get_pruned_tx_blob(cryptonote::transaction &tx) + { + std::stringstream ss; + binary_archive<true> ba(ss); + bool r = tx.serialize_base(ba); + CHECK_AND_ASSERT_MES(r, cryptonote::blobdata(), "Failed to serialize rct signatures base"); + return ss.str(); + } + //------------------------------------------------------------------------------------------------------------------------------ static cryptonote::blobdata get_pruned_tx_blob(const cryptonote::blobdata &blobdata) { cryptonote::transaction tx; @@ -216,14 +225,9 @@ namespace cryptonote if (!cryptonote::parse_and_validate_tx_from_blob(blobdata, tx)) { MERROR("Failed to parse and validate tx from blob"); - return blobdata; + return cryptonote::blobdata(); } - - std::stringstream ss; - binary_archive<true> ba(ss); - bool r = tx.serialize_base(ba); - CHECK_AND_ASSERT_MES(r, blobdata, "Failed to serialize rct signatures base"); - return ss.str(); + return get_pruned_tx_blob(tx); } //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res) @@ -633,7 +637,7 @@ namespace cryptonote crypto::hash tx_hash = *vhi++; e.tx_hash = *txhi++; - blobdata blob = t_serializable_object_to_blob(tx); + blobdata blob = req.prune ? get_pruned_tx_blob(tx) : t_serializable_object_to_blob(tx); e.as_hex = string_tools::buff_to_hex_nodelimer(blob); if (req.decode_as_json) e.as_json = obj_to_json_str(tx); @@ -2078,10 +2082,27 @@ namespace cryptonote //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::on_get_output_distribution(const COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::request& req, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response& res, epee::json_rpc::error& error_resp) { + PERF_TIMER(on_get_output_distribution); try { for (uint64_t amount: req.amounts) { + static struct D + { + boost::mutex mutex; + std::vector<uint64_t> cached_distribution; + uint64_t cached_from, cached_to, cached_start_height, cached_base; + bool cached; + D(): cached_from(0), cached_to(0), cached_start_height(0), cached_base(0), cached(false) {} + } d; + boost::unique_lock<boost::mutex> lock(d.mutex); + + if (d.cached && amount == 0 && d.cached_from == req.from_height && d.cached_to == req.to_height) + { + res.distributions.push_back({amount, d.cached_start_height, d.cached_distribution, d.cached_base}); + continue; + } + std::vector<uint64_t> distribution; uint64_t start_height, base; if (!m_core.get_output_distribution(amount, req.from_height, start_height, distribution, base)) @@ -2090,12 +2111,29 @@ namespace cryptonote error_resp.message = "Failed to get rct distribution"; return false; } + if (req.to_height > 0 && req.to_height >= req.from_height) + { + uint64_t offset = std::max(req.from_height, start_height); + if (offset <= req.to_height && req.to_height - offset + 1 < distribution.size()) + distribution.resize(req.to_height - offset + 1); + } if (req.cumulative) { distribution[0] += base; for (size_t n = 1; n < distribution.size(); ++n) distribution[n] += distribution[n-1]; } + + if (amount == 0) + { + d.cached_from = req.from_height; + d.cached_to = req.to_height; + d.cached_distribution = distribution; + d.cached_start_height = start_height; + d.cached_base = base; + d.cached = true; + } + res.distributions.push_back({amount, start_height, std::move(distribution), base}); } } @@ -2117,7 +2155,7 @@ namespace cryptonote , "Port for RPC server" , std::to_string(config::RPC_DEFAULT_PORT) , {{ &cryptonote::arg_testnet_on, &cryptonote::arg_stagenet_on }} - , [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val) { + , [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val)->std::string { if (testnet_stagenet[0] && defaulted) return std::to_string(config::testnet::RPC_DEFAULT_PORT); else if (testnet_stagenet[1] && defaulted) diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index a5755e062..86e41e047 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -153,7 +153,7 @@ namespace cryptonote MAP_JON_RPC_WE_IF("relay_tx", on_relay_tx, COMMAND_RPC_RELAY_TX, !m_restricted) MAP_JON_RPC_WE_IF("sync_info", on_sync_info, COMMAND_RPC_SYNC_INFO, !m_restricted) MAP_JON_RPC_WE("get_txpool_backlog", on_get_txpool_backlog, COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG) - MAP_JON_RPC_WE_IF("get_output_distribution", on_get_output_distribution, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION, !m_restricted) + MAP_JON_RPC_WE("get_output_distribution", on_get_output_distribution, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION) END_JSON_RPC_MAP() END_URI_MAP2() diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 660fb7889..a97277c0e 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -563,10 +563,12 @@ namespace cryptonote { std::list<std::string> txs_hashes; bool decode_as_json; + bool prune; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(txs_hashes) KV_SERIALIZE(decode_as_json) + KV_SERIALIZE_OPT(prune, false) END_KV_SERIALIZE_MAP() }; @@ -2210,11 +2212,13 @@ namespace cryptonote { std::vector<uint64_t> amounts; uint64_t from_height; + uint64_t to_height; bool cumulative; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(amounts) KV_SERIALIZE_OPT(from_height, (uint64_t)0) + KV_SERIALIZE_OPT(to_height, (uint64_t)0) KV_SERIALIZE_OPT(cumulative, false) END_KV_SERIALIZE_MAP() }; diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 97dadb126..f5a075f54 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -62,6 +62,7 @@ #include "ringct/rctSigs.h" #include "multisig/multisig.h" #include "wallet/wallet_args.h" +#include "version.h" #include <stdexcept> #ifdef WIN32 @@ -1584,6 +1585,12 @@ bool simple_wallet::save_known_rings(const std::vector<std::string> &args) return true; } +bool simple_wallet::version(const std::vector<std::string> &args) +{ + message_writer() << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")"; + return true; +} + bool simple_wallet::set_always_confirm_transfers(const std::vector<std::string> &args/* = std::vector<std::string>()*/) { const auto pwd_container = get_and_verify_password(); @@ -1650,6 +1657,9 @@ bool simple_wallet::set_default_ring_size(const std::vector<std::string> &args/* return true; } + if (ring_size != 0 && ring_size != DEFAULT_MIX+1) + message_writer() << tr("WARNING: this is a non default ring size, which may harm your privacy. Default is recommended."); + const auto pwd_container = get_and_verify_password(); if (pwd_container) { @@ -2332,6 +2342,10 @@ simple_wallet::simple_wallet() boost::bind(&simple_wallet::blackballed, this, _1), tr("blackballed <output public key>"), tr("Checks whether an output is blackballed")); + m_cmd_binder.set_handler("version", + boost::bind(&simple_wallet::version, this, _1), + tr("version"), + tr("Returns version information")); m_cmd_binder.set_handler("help", boost::bind(&simple_wallet::help, this, _1), tr("help [<command>]"), @@ -2974,6 +2988,22 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) // create wallet bool r = new_wallet(vm, "Ledger"); CHECK_AND_ASSERT_MES(r, false, tr("account creation failed")); + // if no block_height is specified, assume its a new account and start it "now" + if(m_wallet->get_refresh_from_block_height() == 0) { + { + tools::scoped_message_writer wrt = tools::msg_writer(); + wrt << tr("No restore height is specified."); + wrt << tr("Assumed you are creating a new account, restore will be done from current estimated blockchain height."); + wrt << tr("Use --restore-height if you want to restore an already setup account from a specific height"); + } + std::string confirm = input_line(tr("Is this okay? (Y/Yes/N/No): ")); + if (std::cin.eof() || !command_line::is_yes(confirm)) + CHECK_AND_ASSERT_MES(false, false, tr("account creation aborted")); + + m_wallet->set_refresh_from_block_height(m_wallet->estimate_blockchain_height()-1); + m_wallet->explicit_refresh_from_block_height(true); + m_restore_height = m_wallet->get_refresh_from_block_height(); + } } else { @@ -2990,7 +3020,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) CHECK_AND_ASSERT_MES(r, false, tr("account creation failed")); } - if (m_restoring && m_generate_from_json.empty()) + if (m_restoring && m_generate_from_json.empty() && m_generate_from_device.empty()) { m_wallet->explicit_refresh_from_block_height(!command_line::is_arg_defaulted(vm, arg_restore_height)); } @@ -3101,6 +3131,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) if (!m_trusted_daemon) message_writer() << (boost::format(tr("Warning: using an untrusted daemon at %s, privacy will be lessened")) % m_wallet->get_daemon_address()).str(); + if (m_wallet->get_ring_database().empty()) + fail_msg_writer() << tr("Failed to initialize ring database: privacy enhancing features will be inactive"); + m_wallet->callback(this); return true; @@ -3385,7 +3418,7 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, try { m_wallet->restore(m_wallet_file, std::move(rc.second).password(), device_name); - message_writer(console_color_white, true) << tr("Generated new on device wallet: ") + message_writer(console_color_white, true) << tr("Generated new wallet on hw device: ") << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); } catch (const std::exception& e) @@ -4581,6 +4614,23 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri if (!print_ring_members(ptx_vector, prompt)) return true; } + bool default_ring_size = true; + for (const auto &ptx: ptx_vector) + { + for (const auto &vin: ptx.tx.vin) + { + if (vin.type() == typeid(txin_to_key)) + { + const txin_to_key& in_to_key = boost::get<txin_to_key>(vin); + if (in_to_key.key_offsets.size() != DEFAULT_MIX + 1) + default_ring_size = false; + } + } + } + if (m_wallet->confirm_non_default_ring_size() && !default_ring_size) + { + prompt << tr("WARNING: this is a non default ring size, which may harm your privacy. Default is recommended."); + } prompt << ENDL << tr("Is this okay? (Y/Yes/N/No): "); std::string accepted = input_line(prompt.str()); @@ -7458,7 +7508,7 @@ int main(int argc, char* argv[]) const auto vm = wallet_args::main( argc, argv, "monero-wallet-cli [--wallet-file=<file>|--generate-new-wallet=<file>] [<COMMAND>]", - sw::tr("This is the command line monero wallet. It needs to connect to a monero\ndaemon to work correctly."), + sw::tr("This is the command line monero wallet. It needs to connect to a monero\ndaemon to work correctly.\nWARNING: Do not reuse your Monero keys on an another fork, UNLESS this fork has key reuse mitigations built in. Doing so will harm your privacy."), desc_params, positional_options, [](const std::string &s, bool emphasis){ tools::scoped_message_writer(emphasis ? epee::console_color_white : epee::console_color_default, true) << s; }, diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index f26f69353..39a91c5f5 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -218,6 +218,7 @@ namespace cryptonote bool blackball(const std::vector<std::string>& args); bool unblackball(const std::vector<std::string>& args); bool blackballed(const std::vector<std::string>& args); + bool version(const std::vector<std::string>& args); uint64_t get_daemon_blockchain_height(std::string& err); bool try_connect_to_daemon(bool silent = false, uint32_t* version = nullptr); diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index b02884f67..b78a471b9 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -60,7 +60,7 @@ namespace Monero { namespace { // copy-pasted from simplewallet - static const size_t DEFAULT_MIXIN = 4; + static const size_t DEFAULT_MIXIN = 6; static const int DEFAULT_REFRESH_INTERVAL_MILLIS = 1000 * 10; // limit maximum refresh interval as one minute static const int MAX_REFRESH_INTERVAL_MILLIS = 1000 * 60 * 1; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 4b7e6dd93..c26aecb14 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -110,7 +110,7 @@ using namespace cryptonote; #define MULTISIG_EXPORT_FILE_MAGIC "Monero multisig export\001" -#define SEGREGATION_FORK_HEIGHT 1564965 +#define SEGREGATION_FORK_HEIGHT 1546000 #define TESTNET_SEGREGATION_FORK_HEIGHT 1000000 #define STAGENET_SEGREGATION_FORK_HEIGHT 1000000 #define SEGREGATION_FORK_VICINITY 1500 /* blocks */ @@ -145,7 +145,7 @@ struct options { "shared-ringdb-dir", tools::wallet2::tr("Set shared ring database path"), get_default_ringdb_path(), testnet, - [](bool testnet, bool defaulted, std::string val) { + [](bool testnet, bool defaulted, std::string val)->std::string { if (testnet) return (boost::filesystem::path(val) / "testnet").string(); return val; @@ -653,6 +653,7 @@ wallet2::wallet2(network_type nettype, bool restricted): m_refresh_from_block_height(0), m_explicit_refresh_from_block_height(true), m_confirm_missing_payment_id(true), + m_confirm_non_default_ring_size(true), m_ask_password(true), m_min_output_count(0), m_min_output_value(0), @@ -1007,13 +1008,16 @@ void wallet2::set_unspent(size_t idx) //---------------------------------------------------------------------------------------------------- void wallet2::check_acc_out_precomp(const tx_out &o, const crypto::key_derivation &derivation, const std::vector<crypto::key_derivation> &additional_derivations, size_t i, tx_scan_info_t &tx_scan_info) const { + hw::device &hwdev = m_account.get_device(); + boost::unique_lock<hw::device> hwdev_lock (hwdev); + hwdev.set_mode(hw::device::TRANSACTION_PARSE); if (o.target.type() != typeid(txout_to_key)) { tx_scan_info.error = true; LOG_ERROR("wrong type id in transaction out"); return; } - tx_scan_info.received = is_out_to_acc_precomp(m_subaddresses, boost::get<txout_to_key>(o.target).key, derivation, additional_derivations, i, m_account.get_device()); + tx_scan_info.received = is_out_to_acc_precomp(m_subaddresses, boost::get<txout_to_key>(o.target).key, derivation, additional_derivations, i, hwdev); if(tx_scan_info.received) { tx_scan_info.money_transfered = o.amount; // may be 0 for ringct outputs @@ -1080,9 +1084,15 @@ void wallet2::scan_output(const cryptonote::transaction &tx, const crypto::publi //---------------------------------------------------------------------------------------------------- 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, bool double_spend_seen) { - // In this function, tx (probably) only contains the base information - // (that is, the prunable stuff may or may not be included) + //ensure device is let in NONE mode in any case + hw::device &hwdev = m_account.get_device(); + + boost::unique_lock<hw::device> hwdev_lock (hwdev); + hw::reset_mode rst(hwdev); + hwdev_lock.unlock(); + // In this function, tx (probably) only contains the base information + // (that is, the prunable stuff may or may not be included) if (!miner_tx && !pool) process_unconfirmed(txid, tx, height); std::vector<size_t> outs; @@ -1119,8 +1129,10 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote tools::threadpool& tpool = tools::threadpool::getInstance(); tools::threadpool::waiter waiter; const cryptonote::account_keys& keys = m_account.get_keys(); - hw::device &hwdev = m_account.get_device(); crypto::key_derivation derivation; + + hwdev_lock.lock(); + hwdev.set_mode(hw::device::TRANSACTION_PARSE); if (!hwdev.generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation)) { MWARNING("Failed to generate key derivation from tx pubkey, skipping"); @@ -1140,6 +1152,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote additional_derivations.pop_back(); } } + hwdev_lock.unlock(); if (miner_tx && m_refresh_type == RefreshNoCoinbase) { @@ -1161,16 +1174,19 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote std::ref(tx_scan_info[i]))); } waiter.wait(); - // then scan all outputs from 0 + hwdev_lock.lock(); + hwdev.set_mode(hw::device::NONE); for (size_t i = 0; i < tx.vout.size(); ++i) { THROW_WALLET_EXCEPTION_IF(tx_scan_info[i].error, error::acc_outs_lookup_error, tx, tx_pub_key, m_account.get_keys()); if (tx_scan_info[i].received) { + hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys, derivation, additional_derivations); scan_output(tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs); } } + hwdev_lock.unlock(); } } else if (tx.vout.size() > 1 && tools::threadpool::getInstance().get_max_concurrency() > 1) @@ -1181,14 +1197,19 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote std::ref(tx_scan_info[i]))); } waiter.wait(); + + hwdev_lock.lock(); + hwdev.set_mode(hw::device::NONE); for (size_t i = 0; i < tx.vout.size(); ++i) { THROW_WALLET_EXCEPTION_IF(tx_scan_info[i].error, error::acc_outs_lookup_error, tx, tx_pub_key, m_account.get_keys()); if (tx_scan_info[i].received) { + hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys, derivation, additional_derivations); scan_output(tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs); } } + hwdev_lock.unlock(); } else { @@ -1198,7 +1219,11 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote THROW_WALLET_EXCEPTION_IF(tx_scan_info[i].error, error::acc_outs_lookup_error, tx, tx_pub_key, m_account.get_keys()); if (tx_scan_info[i].received) { + hwdev_lock.lock(); + hwdev.set_mode(hw::device::NONE); + hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys, derivation, additional_derivations); scan_output(tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs); + hwdev_lock.unlock(); } } } @@ -2010,6 +2035,7 @@ void wallet2::update_pool_state(bool refreshed) req.txs_hashes.push_back(epee::string_tools::pod_to_hex(p.first)); MDEBUG("asking for " << txids.size() << " transactions"); req.decode_as_json = false; + req.prune = false; m_daemon_rpc_mutex.lock(); bool r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout); m_daemon_rpc_mutex.unlock(); @@ -2560,6 +2586,9 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable value2.SetInt(m_confirm_missing_payment_id ? 1 :0); json.AddMember("confirm_missing_payment_id", value2, json.GetAllocator()); + value2.SetInt(m_confirm_non_default_ring_size ? 1 :0); + json.AddMember("confirm_non_default_ring_size", value2, json.GetAllocator()); + value2.SetInt(m_ask_password ? 1 :0); json.AddMember("ask_password", value2, json.GetAllocator()); @@ -2599,6 +2628,12 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable value2.SetUint(m_segregation_height); json.AddMember("segregation_height", value2, json.GetAllocator()); + value2.SetUint(m_subaddress_lookahead_major); + json.AddMember("subaddress_lookahead_major", value2, json.GetAllocator()); + + value2.SetUint(m_subaddress_lookahead_minor); + json.AddMember("subaddress_lookahead_minor", value2, json.GetAllocator()); + // Serialize the JSON object rapidjson::StringBuffer buffer; rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); @@ -2661,6 +2696,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ m_auto_refresh = true; m_refresh_type = RefreshType::RefreshDefault; m_confirm_missing_payment_id = true; + m_confirm_non_default_ring_size = true; m_ask_password = true; m_min_output_count = 0; m_min_output_value = 0; @@ -2669,6 +2705,11 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ m_confirm_backlog_threshold = 0; m_confirm_export_overwrite = true; m_auto_low_priority = true; + m_segregate_pre_fork_outputs = true; + m_key_reuse_mitigation2 = true; + m_segregation_height = 0; + m_subaddress_lookahead_major = SUBADDRESS_LOOKAHEAD_MAJOR; + m_subaddress_lookahead_minor = SUBADDRESS_LOOKAHEAD_MINOR; m_key_on_device = false; } else if(json.IsObject()) @@ -2761,6 +2802,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ m_refresh_from_block_height = field_refresh_height; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, confirm_missing_payment_id, int, Int, false, true); m_confirm_missing_payment_id = field_confirm_missing_payment_id; + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, confirm_non_default_ring_size, int, Int, false, true); + m_confirm_non_default_ring_size = field_confirm_non_default_ring_size; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, ask_password, int, Int, false, true); m_ask_password = field_ask_password; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, default_decimal_point, int, Int, false, CRYPTONOTE_DISPLAY_DECIMAL_POINT); @@ -2785,6 +2828,16 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ (boost::format("%s wallet cannot be opened as %s wallet") % (field_nettype == 0 ? "Mainnet" : field_nettype == 1 ? "Testnet" : "Stagenet") % (m_nettype == MAINNET ? "mainnet" : m_nettype == TESTNET ? "testnet" : "stagenet")).str()); + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, segregate_pre_fork_outputs, int, Int, false, true); + m_segregate_pre_fork_outputs = field_segregate_pre_fork_outputs; + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, key_reuse_mitigation2, int, Int, false, true); + m_key_reuse_mitigation2 = field_key_reuse_mitigation2; + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, segregation_height, int, Uint, false, 0); + m_segregation_height = field_segregation_height; + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_major, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MAJOR); + m_subaddress_lookahead_major = field_subaddress_lookahead_major; + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_minor, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MINOR); + m_subaddress_lookahead_minor = field_subaddress_lookahead_minor; } else { @@ -5467,45 +5520,61 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<crypto } } -void wallet2::set_ring_database(const std::string &filename) +bool wallet2::set_ring_database(const std::string &filename) { m_ring_database = filename; MINFO("ringdb path set to " << filename); m_ringdb.reset(); - cryptonote::block b; - generate_genesis(b); if (!m_ring_database.empty()) - m_ringdb.reset(new tools::ringdb(m_ring_database, epee::string_tools::pod_to_hex(get_block_hash(b)))); + { + try + { + cryptonote::block b; + generate_genesis(b); + m_ringdb.reset(new tools::ringdb(m_ring_database, epee::string_tools::pod_to_hex(get_block_hash(b)))); + } + catch (const std::exception &e) + { + MERROR("Failed to initialize ringdb: " << e.what()); + m_ring_database = ""; + return false; + } + } + return true; } bool wallet2::add_rings(const crypto::chacha_key &key, const cryptonote::transaction_prefix &tx) { if (!m_ringdb) - return true; - return m_ringdb->add_rings(key, tx); + return false; + try { return m_ringdb->add_rings(key, tx); } + catch (const std::exception &e) { return false; } } bool wallet2::add_rings(const cryptonote::transaction_prefix &tx) { crypto::chacha_key key; generate_chacha_key_from_secret_keys(key); - return add_rings(key, tx); + try { return add_rings(key, tx); } + catch (const std::exception &e) { return false; } } bool wallet2::remove_rings(const cryptonote::transaction_prefix &tx) { if (!m_ringdb) - return true; + return false; crypto::chacha_key key; generate_chacha_key_from_secret_keys(key); - return m_ringdb->remove_rings(key, tx); + try { return m_ringdb->remove_rings(key, tx); } + catch (const std::exception &e) { return false; } } bool wallet2::get_ring(const crypto::chacha_key &key, const crypto::key_image &key_image, std::vector<uint64_t> &outs) { if (!m_ringdb) - return true; - return m_ringdb->get_ring(key, key_image, outs); + return false; + try { return m_ringdb->get_ring(key, key_image, outs); } + catch (const std::exception &e) { return false; } } bool wallet2::get_rings(const crypto::hash &txid, std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> &outs) @@ -5536,18 +5605,20 @@ bool wallet2::get_ring(const crypto::key_image &key_image, std::vector<uint64_t> crypto::chacha_key key; generate_chacha_key_from_secret_keys(key); - return get_ring(key, key_image, outs); + try { return get_ring(key, key_image, outs); } + catch (const std::exception &e) { return false; } } bool wallet2::set_ring(const crypto::key_image &key_image, const std::vector<uint64_t> &outs, bool relative) { if (!m_ringdb) - return true; + return false; crypto::chacha_key key; generate_chacha_key_from_secret_keys(key); - return m_ringdb->set_ring(key, key_image, outs, relative); + try { return m_ringdb->set_ring(key, key_image, outs, relative); } + catch (const std::exception &e) { return false; } } bool wallet2::find_and_save_rings(bool force) @@ -5555,7 +5626,7 @@ bool wallet2::find_and_save_rings(bool force) if (!force && m_ring_history_saved) return true; if (!m_ringdb) - return true; + return false; COMMAND_RPC_GET_TRANSACTIONS::request req = AUTO_VAL_INIT(req); COMMAND_RPC_GET_TRANSACTIONS::response res = AUTO_VAL_INIT(res); @@ -5563,39 +5634,49 @@ bool wallet2::find_and_save_rings(bool force) MDEBUG("Finding and saving rings..."); // get payments we made + std::vector<crypto::hash> txs_hashes; std::list<std::pair<crypto::hash,wallet2::confirmed_transfer_details>> payments; get_payments_out(payments, 0, std::numeric_limits<uint64_t>::max(), boost::none, std::set<uint32_t>()); for (const std::pair<crypto::hash,wallet2::confirmed_transfer_details> &entry: payments) { const crypto::hash &txid = entry.first; - req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid)); - } - - MDEBUG("Found " << std::to_string(req.txs_hashes.size()) << " transactions"); - - // get those transactions from the daemon - req.decode_as_json = false; - bool r; - { - const boost::lock_guard<boost::mutex> lock{m_daemon_rpc_mutex}; - r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout); + txs_hashes.push_back(txid); } - THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions"); - THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions"); - THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::wallet_internal_error, "gettransactions"); - THROW_WALLET_EXCEPTION_IF(res.txs.size() != req.txs_hashes.size(), error::wallet_internal_error, - "daemon returned wrong response for gettransactions, wrong txs count = " + - std::to_string(res.txs.size()) + ", expected " + std::to_string(req.txs_hashes.size())); - MDEBUG("Scanning " << res.txs.size() << " transactions"); + MDEBUG("Found " << std::to_string(txs_hashes.size()) << " transactions"); crypto::chacha_key key; generate_chacha_key_from_secret_keys(key); - auto it = req.txs_hashes.begin(); - for (size_t i = 0; i < res.txs.size(); ++i, ++it) + // get those transactions from the daemon + static const size_t SLICE_SIZE = 200; + for (size_t slice = 0; slice < txs_hashes.size(); slice += SLICE_SIZE) { + req.decode_as_json = false; + req.prune = true; + req.txs_hashes.clear(); + size_t ntxes = slice + SLICE_SIZE > txs_hashes.size() ? txs_hashes.size() - slice : SLICE_SIZE; + for (size_t s = slice; s < slice + ntxes; ++s) + req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txs_hashes[s])); + bool r; + { + const boost::lock_guard<boost::mutex> lock{m_daemon_rpc_mutex}; + r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout); + } + THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions"); + THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions"); + THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::wallet_internal_error, "gettransactions"); + THROW_WALLET_EXCEPTION_IF(res.txs.size() != req.txs_hashes.size(), error::wallet_internal_error, + "daemon returned wrong response for gettransactions, wrong txs count = " + + std::to_string(res.txs.size()) + ", expected " + std::to_string(req.txs_hashes.size())); + + MDEBUG("Scanning " << res.txs.size() << " transactions"); + THROW_WALLET_EXCEPTION_IF(slice + res.txs.size() > txs_hashes.size(), error::wallet_internal_error, "Unexpected tx array size"); + auto it = req.txs_hashes.begin(); + for (size_t i = 0; i < res.txs.size(); ++i, ++it) + { const auto &tx_info = res.txs[i]; + THROW_WALLET_EXCEPTION_IF(tx_info.tx_hash != epee::string_tools::pod_to_hex(txs_hashes[slice + i]), error::wallet_internal_error, "Wrong txid received"); THROW_WALLET_EXCEPTION_IF(tx_info.tx_hash != *it, error::wallet_internal_error, "Wrong txid received"); cryptonote::blobdata bd; THROW_WALLET_EXCEPTION_IF(!epee::string_tools::parse_hexstr_to_binbuff(tx_info.as_hex, bd), error::wallet_internal_error, "failed to parse tx from hexstr"); @@ -5604,9 +5685,10 @@ bool wallet2::find_and_save_rings(bool force) THROW_WALLET_EXCEPTION_IF(!cryptonote::parse_and_validate_tx_from_blob(bd, tx, tx_hash, tx_prefix_hash), error::wallet_internal_error, "failed to parse tx from blob"); THROW_WALLET_EXCEPTION_IF(epee::string_tools::pod_to_hex(tx_hash) != tx_info.tx_hash, error::wallet_internal_error, "txid mismatch"); THROW_WALLET_EXCEPTION_IF(!add_rings(key, tx), error::wallet_internal_error, "Failed to save ring"); + } } - MINFO("Found and saved rings for " << res.txs.size() << " transactions"); + MINFO("Found and saved rings for " << txs_hashes.size() << " transactions"); m_ring_history_saved = true; return true; } @@ -5614,34 +5696,41 @@ bool wallet2::find_and_save_rings(bool force) bool wallet2::blackball_output(const crypto::public_key &output) { if (!m_ringdb) - return true; - return m_ringdb->blackball(output); + return false; + try { return m_ringdb->blackball(output); } + catch (const std::exception &e) { return false; } } bool wallet2::set_blackballed_outputs(const std::vector<crypto::public_key> &outputs, bool add) { if (!m_ringdb) - return true; - bool ret = true; - if (!add) - ret &= m_ringdb->clear_blackballs(); - for (const auto &output: outputs) - ret &= m_ringdb->blackball(output); - return ret; + return false; + try + { + bool ret = true; + if (!add) + ret &= m_ringdb->clear_blackballs(); + for (const auto &output: outputs) + ret &= m_ringdb->blackball(output); + return ret; + } + catch (const std::exception &e) { return false; } } bool wallet2::unblackball_output(const crypto::public_key &output) { if (!m_ringdb) - return true; - return m_ringdb->unblackball(output); + return false; + try { return m_ringdb->unblackball(output); } + catch (const std::exception &e) { return false; } } bool wallet2::is_output_blackballed(const crypto::public_key &output) const { if (!m_ringdb) - return true; - return m_ringdb->blackballed(output); + return false; + try { return m_ringdb->blackballed(output); } + catch (const std::exception &e) { return false; } } bool wallet2::tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, uint64_t global_index, const crypto::public_key& output_public_key, const rct::key& mask, uint64_t real_index, bool unlocked) const @@ -5785,6 +5874,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> boost::optional<std::string> result = m_node_rpc_proxy.get_height(height); throw_on_rpc_response_error(result, "get_info"); bool is_shortly_after_segregation_fork = height >= segregation_fork_height && height < segregation_fork_height + SEGREGATION_FORK_VICINITY; + bool is_after_segregation_fork = height >= segregation_fork_height; // get histogram for the amounts we need cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request req_t = AUTO_VAL_INIT(req_t); @@ -5805,7 +5895,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> // if we want to segregate fake outs pre or post fork, get distribution std::unordered_map<uint64_t, std::pair<uint64_t, uint64_t>> segregation_limit; - if (m_segregate_pre_fork_outputs || m_key_reuse_mitigation2) + if (is_after_segregation_fork && (m_segregate_pre_fork_outputs || m_key_reuse_mitigation2)) { cryptonote::COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::request req_t = AUTO_VAL_INIT(req_t); cryptonote::COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response resp_t = AUTO_VAL_INIT(resp_t); @@ -5814,10 +5904,11 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> std::sort(req_t.amounts.begin(), req_t.amounts.end()); auto end = std::unique(req_t.amounts.begin(), req_t.amounts.end()); req_t.amounts.resize(std::distance(req_t.amounts.begin(), end)); - req_t.from_height = segregation_fork_height >= RECENT_OUTPUT_ZONE ? height >= (segregation_fork_height ? segregation_fork_height : height) - RECENT_OUTPUT_BLOCKS : 0; + req_t.from_height = std::max<uint64_t>(segregation_fork_height, RECENT_OUTPUT_BLOCKS) - RECENT_OUTPUT_BLOCKS; + req_t.to_height = segregation_fork_height + 1; req_t.cumulative = true; m_daemon_rpc_mutex.lock(); - bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_distribution", req_t, resp_t, m_http_client, rpc_timeout); + bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_distribution", req_t, resp_t, m_http_client, rpc_timeout * 1000); m_daemon_rpc_mutex.unlock(); THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "transfer_selected"); THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_distribution"); @@ -5834,6 +5925,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> { THROW_WALLET_EXCEPTION_IF(d.start_height > segregation_fork_height, error::get_output_distribution, "Distribution start_height too high"); THROW_WALLET_EXCEPTION_IF(segregation_fork_height - d.start_height >= d.distribution.size(), error::get_output_distribution, "Distribution size too small"); + THROW_WALLET_EXCEPTION_IF(segregation_fork_height - RECENT_OUTPUT_BLOCKS - d.start_height >= d.distribution.size(), error::get_output_distribution, "Distribution size too small"); THROW_WALLET_EXCEPTION_IF(segregation_fork_height <= RECENT_OUTPUT_BLOCKS, error::wallet_internal_error, "Fork height too low"); THROW_WALLET_EXCEPTION_IF(segregation_fork_height - RECENT_OUTPUT_BLOCKS < d.start_height, error::get_output_distribution, "Bad start height"); uint64_t till_fork = d.distribution[segregation_fork_height - d.start_height]; @@ -5872,7 +5964,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> float pre_fork_num_out_ratio = 0.0f; float post_fork_num_out_ratio = 0.0f; - if (m_segregate_pre_fork_outputs && output_is_pre_fork) + if (is_after_segregation_fork && m_segregate_pre_fork_outputs && output_is_pre_fork) { num_outs = segregation_limit[amount].first; num_recent_outs = segregation_limit[amount].second; @@ -5892,7 +5984,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> break; } } - if (m_key_reuse_mitigation2) + if (is_after_segregation_fork && m_key_reuse_mitigation2) { if (output_is_pre_fork) { @@ -6107,7 +6199,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> uint64_t num_outs = 0; const uint64_t amount = td.is_rct() ? 0 : td.amount(); const bool output_is_pre_fork = td.m_block_height < segregation_fork_height; - if (m_segregate_pre_fork_outputs && output_is_pre_fork) + if (is_after_segregation_fork && m_segregate_pre_fork_outputs && output_is_pre_fork) num_outs = segregation_limit[amount].first; else for (const auto &he: resp_t.histogram) { @@ -7224,6 +7316,11 @@ bool wallet2::light_wallet_key_image_is_ours(const crypto::key_image& key_image, // usable balance. std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, bool trusted_daemon) { + //ensure device is let in NONE mode in any case + hw::device &hwdev = m_account.get_device(); + boost::unique_lock<hw::device> hwdev_lock (hwdev); + hw::reset_mode rst(hwdev); + if(m_light_wallet) { // Populate m_transfers light_wallet_get_unspent_outs(); @@ -7441,8 +7538,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp unsigned int original_output_index = 0; std::vector<size_t>* unused_transfers_indices = &unused_transfers_indices_per_subaddr[0].second; std::vector<size_t>* unused_dust_indices = &unused_dust_indices_per_subaddr[0].second; - hw::device &hwdev = m_account.get_device(); - hwdev.set_signature_mode(hw::device::SIGNATURE_FAKE); + + hwdev.set_mode(hw::device::TRANSACTION_CREATE_FAKE); while ((!dsts.empty() && dsts[0].amount > 0) || adding_fee || !preferred_inputs.empty() || should_pick_a_second_output(use_rct, txes.back().selected_transfers.size(), *unused_transfers_indices, *unused_dust_indices)) { TX &tx = txes.back(); @@ -7671,7 +7768,7 @@ skip_tx: LOG_PRINT_L1("Done creating " << txes.size() << " transactions, " << print_money(accumulated_fee) << " total fee, " << print_money(accumulated_change) << " total change"); - hwdev.set_signature_mode(hw::device::SIGNATURE_REAL); + hwdev.set_mode(hw::device::TRANSACTION_CREATE_REAL); for (std::vector<TX>::iterator i = txes.begin(); i != txes.end(); ++i) { TX &tx = *i; @@ -7802,6 +7899,11 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypt std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const cryptonote::account_public_address &address, bool is_subaddress, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, bool trusted_daemon) { + //ensure device is let in NONE mode in any case + hw::device &hwdev = m_account.get_device(); + boost::unique_lock<hw::device> hwdev_lock (hwdev); + hw::reset_mode rst(hwdev); + uint64_t accumulated_fee, accumulated_outputs, accumulated_change; struct TX { std::vector<size_t> selected_transfers; @@ -7834,8 +7936,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton needed_fee = 0; // while we have something to send - hw::device &hwdev = m_account.get_device(); - hwdev.set_signature_mode(hw::device::SIGNATURE_FAKE); + hwdev.set_mode(hw::device::TRANSACTION_CREATE_FAKE); while (!unused_dust_indices.empty() || !unused_transfers_indices.empty()) { TX &tx = txes.back(); @@ -7921,7 +8022,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton LOG_PRINT_L1("Done creating " << txes.size() << " transactions, " << print_money(accumulated_fee) << " total fee, " << print_money(accumulated_change) << " total change"); - hwdev.set_signature_mode(hw::device::SIGNATURE_REAL); + hwdev.set_mode(hw::device::TRANSACTION_CREATE_REAL); for (std::vector<TX>::iterator i = txes.begin(); i != txes.end(); ++i) { TX &tx = *i; @@ -8155,6 +8256,7 @@ std::string wallet2::get_spend_proof(const crypto::hash &txid, const std::string COMMAND_RPC_GET_TRANSACTIONS::request req = AUTO_VAL_INIT(req); req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid)); req.decode_as_json = false; + req.prune = false; COMMAND_RPC_GET_TRANSACTIONS::response res = AUTO_VAL_INIT(res); bool r; { @@ -8274,6 +8376,7 @@ bool wallet2::check_spend_proof(const crypto::hash &txid, const std::string &mes COMMAND_RPC_GET_TRANSACTIONS::request req = AUTO_VAL_INIT(req); req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid)); req.decode_as_json = false; + req.prune = false; COMMAND_RPC_GET_TRANSACTIONS::response res = AUTO_VAL_INIT(res); bool r; { @@ -8396,6 +8499,8 @@ void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_de COMMAND_RPC_GET_TRANSACTIONS::request req; COMMAND_RPC_GET_TRANSACTIONS::response res; req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid)); + req.decode_as_json = false; + req.prune = false; m_daemon_rpc_mutex.lock(); bool ok = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client); m_daemon_rpc_mutex.unlock(); @@ -8532,6 +8637,8 @@ std::string wallet2::get_tx_proof(const crypto::hash &txid, const cryptonote::ac COMMAND_RPC_GET_TRANSACTIONS::request req; COMMAND_RPC_GET_TRANSACTIONS::response res; req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid)); + req.decode_as_json = false; + req.prune = false; m_daemon_rpc_mutex.lock(); bool ok = net_utils::invoke_http_json("/gettransactions", req, res, m_http_client); m_daemon_rpc_mutex.unlock(); @@ -8642,6 +8749,8 @@ bool wallet2::check_tx_proof(const crypto::hash &txid, const cryptonote::account COMMAND_RPC_GET_TRANSACTIONS::request req; COMMAND_RPC_GET_TRANSACTIONS::response res; req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid)); + req.decode_as_json = false; + req.prune = false; m_daemon_rpc_mutex.lock(); bool ok = net_utils::invoke_http_json("/gettransactions", req, res, m_http_client); m_daemon_rpc_mutex.unlock(); @@ -8875,6 +8984,8 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr COMMAND_RPC_GET_TRANSACTIONS::response gettx_res; for (size_t i = 0; i < proofs.size(); ++i) gettx_req.txs_hashes.push_back(epee::string_tools::pod_to_hex(proofs[i].txid)); + gettx_req.decode_as_json = false; + gettx_req.prune = false; m_daemon_rpc_mutex.lock(); bool ok = net_utils::invoke_http_json("/gettransactions", gettx_req, gettx_res, m_http_client); m_daemon_rpc_mutex.unlock(); @@ -9449,6 +9560,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag COMMAND_RPC_GET_TRANSACTIONS::request gettxs_req; COMMAND_RPC_GET_TRANSACTIONS::response gettxs_res; gettxs_req.decode_as_json = false; + gettxs_req.prune = 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(); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index abc7bb538..69b63876a 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -874,6 +874,8 @@ namespace tools void key_reuse_mitigation2(bool value) { m_key_reuse_mitigation2 = value; } uint64_t segregation_height() const { return m_segregation_height; } void segregation_height(uint64_t height) { m_segregation_height = height; } + bool confirm_non_default_ring_size() const { return m_confirm_non_default_ring_size; } + void confirm_non_default_ring_size(bool always) { m_confirm_non_default_ring_size = always; } bool get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys) const; void check_tx_key(const crypto::hash &txid, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, const cryptonote::account_public_address &address, uint64_t &received, bool &in_pool, uint64_t &confirmations); @@ -1061,7 +1063,7 @@ namespace tools return epee::net_utils::invoke_http_json_rpc(uri, method_name, req, res, m_http_client, timeout, http_method, req_id); } - void set_ring_database(const std::string &filename); + bool set_ring_database(const std::string &filename); const std::string get_ring_database() const { return m_ring_database; } bool get_ring(const crypto::key_image &key_image, std::vector<uint64_t> &outs); bool get_rings(const crypto::hash &txid, std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> &outs); @@ -1194,6 +1196,7 @@ namespace tools // m_refresh_from_block_height was defaulted to zero.*/ bool m_explicit_refresh_from_block_height; bool m_confirm_missing_payment_id; + bool m_confirm_non_default_ring_size; bool m_ask_password; uint32_t m_min_output_count; uint64_t m_min_output_value; |