diff options
-rw-r--r-- | cmake/FindReadline.cmake | 47 | ||||
-rw-r--r-- | src/blockchain_db/blockchain_db.h | 5 | ||||
-rw-r--r-- | src/blockchain_db/lmdb/db_lmdb.cpp | 8 | ||||
-rw-r--r-- | src/blockchain_db/lmdb/db_lmdb.h | 2 | ||||
-rw-r--r-- | src/cryptonote_core/blockchain.cpp | 4 | ||||
-rw-r--r-- | src/cryptonote_core/blockchain.h | 2 | ||||
-rw-r--r-- | src/cryptonote_core/tx_pool.cpp | 39 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.cpp | 17 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 50 | ||||
-rw-r--r-- | tests/unit_tests/hardfork.cpp | 2 |
10 files changed, 119 insertions, 57 deletions
diff --git a/cmake/FindReadline.cmake b/cmake/FindReadline.cmake index cdce0bfca..7a11a270a 100644 --- a/cmake/FindReadline.cmake +++ b/cmake/FindReadline.cmake @@ -36,14 +36,18 @@ find_library(Readline_LIBRARY NO_DEFAULT_PATH ) -if(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY) +find_library(Termcap_LIBRARY + NAMES tinfo termcap ncursesw ncurses cursesw curses +) + +if(Readline_INCLUDE_DIR AND Readline_LIBRARY) set(READLINE_FOUND TRUE) -else(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY) +else(Readline_INCLUDE_DIR AND Readline_LIBRARY) FIND_LIBRARY(Readline_LIBRARY NAMES readline PATHS Readline_ROOT_DIR) include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Readline DEFAULT_MSG Readline_INCLUDE_DIR Readline_LIBRARY ) MARK_AS_ADVANCED(Readline_INCLUDE_DIR Readline_LIBRARY) -endif(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY) +endif(Readline_INCLUDE_DIR AND Readline_LIBRARY) mark_as_advanced( Readline_ROOT_DIR @@ -53,22 +57,25 @@ mark_as_advanced( set(CMAKE_REQUIRED_INCLUDES ${Readline_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${Readline_LIBRARY}) -INCLUDE(CheckCXXSourceCompiles) -CHECK_CXX_SOURCE_COMPILES( -" -#include <stdio.h> -#include <readline/readline.h> -int -main() -{ - char * s = rl_copy_text(0, 0); -} -" GNU_READLINE_FOUND) -if(NOT Readline_LIBRARY) - set(Readline_LIBRARY "") -endif() +include(CheckFunctionExists) +check_function_exists(rl_copy_text HAVE_COPY_TEXT) +check_function_exists(rl_filename_completion_function HAVE_COMPLETION_FUNCTION) + +if(NOT HAVE_COMPLETION_FUNCTION) + unset(READLINE_FOUND) + set(CMAKE_REQUIRED_LIBRARIES ${Readline_LIBRARY} ${Termcap_LIBRARY}) + check_function_exists(rl_copy_text HAVE_COPY_TEXT_TC) + check_function_exists(rl_filename_completion_function HAVE_COMPLETION_FUNCTION_TC) + set(HAVE_COMPLETION_FUNCTION ${HAVE_COMPLETION_FUNCTION_TC}) + set(HAVE_COPY_TEXT ${HAVE_COPY_TEXT_TC}) + if(HAVE_COMPLETION_FUNCTION) + set(Readline_LIBRARY ${Readline_LIBRARY} ${Termcap_LIBRARY}) + endif(HAVE_COMPLETION_FUNCTION) +endif(NOT HAVE_COMPLETION_FUNCTION) + +if(HAVE_COMPLETION_FUNCTION AND HAVE_COPY_TEXT) + set(GNU_READLINE_FOUND TRUE) + set(READLINE_FOUND TRUE) +endif(HAVE_COMPLETION_FUNCTION AND HAVE_COPY_TEXT) -if(Readline_LIBRARY AND OPENBSD) - list(APPEND EXTRA_LIBRARIES curses) -endif() diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index 88034a927..33c3341fa 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -1333,10 +1333,11 @@ public: * @brief get a txpool transaction's metadata * * @param txid the transaction id of the transation to lookup + * @param meta the metadata to return * - * @return the metadata associated with that transaction + * @return true if the tx meta was found, false otherwise */ - virtual txpool_tx_meta_t get_txpool_tx_meta(const crypto::hash& txid) const = 0; + virtual bool get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const = 0; /** * @brief get a txpool transaction's blob diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 931bbec4b..d19399bec 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -1621,7 +1621,7 @@ void BlockchainLMDB::remove_txpool_tx(const crypto::hash& txid) } } -txpool_tx_meta_t BlockchainLMDB::get_txpool_tx_meta(const crypto::hash& txid) const +bool BlockchainLMDB::get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); check_open(); @@ -1632,12 +1632,14 @@ txpool_tx_meta_t BlockchainLMDB::get_txpool_tx_meta(const crypto::hash& txid) co MDB_val k = {sizeof(txid), (void *)&txid}; MDB_val v; auto result = mdb_cursor_get(m_cur_txpool_meta, &k, &v, MDB_SET); + if (result == MDB_NOTFOUND) + return false; if (result != 0) throw1(DB_ERROR(lmdb_error("Error finding txpool tx meta: ", result).c_str())); - const txpool_tx_meta_t meta = *(const txpool_tx_meta_t*)v.mv_data; + meta = *(const txpool_tx_meta_t*)v.mv_data; TXN_POSTFIX_RDONLY(); - return meta; + return true; } bool BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h index 85b62b5db..ecd14f11b 100644 --- a/src/blockchain_db/lmdb/db_lmdb.h +++ b/src/blockchain_db/lmdb/db_lmdb.h @@ -246,7 +246,7 @@ public: virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const; virtual bool txpool_has_tx(const crypto::hash &txid) const; virtual void remove_txpool_tx(const crypto::hash& txid); - virtual txpool_tx_meta_t get_txpool_tx_meta(const crypto::hash& txid) const; + virtual bool get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const; virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const; virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const; virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob = false, bool include_unrelayed_txes = true) const; diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 709c5e852..4af987c3b 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -4198,9 +4198,9 @@ uint64_t Blockchain::get_txpool_tx_count(bool include_unrelayed_txes) const return m_db->get_txpool_tx_count(include_unrelayed_txes); } -txpool_tx_meta_t Blockchain::get_txpool_tx_meta(const crypto::hash& txid) const +bool Blockchain::get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const { - return m_db->get_txpool_tx_meta(txid); + return m_db->get_txpool_tx_meta(txid, meta); } bool Blockchain::get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 2d5307ac0..25e573a2c 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -914,7 +914,7 @@ namespace cryptonote void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t &meta); void remove_txpool_tx(const crypto::hash &txid); uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const; - txpool_tx_meta_t get_txpool_tx_meta(const crypto::hash& txid) const; + bool get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const; bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const; cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const; bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false, bool include_unrelayed_txes = true) const; diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index e6f217463..8773c1f74 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -371,7 +371,12 @@ namespace cryptonote try { LockedTXN lock(m_blockchain); - txpool_tx_meta_t meta = m_blockchain.get_txpool_tx_meta(id); + txpool_tx_meta_t meta; + if (!m_blockchain.get_txpool_tx_meta(id, meta)) + { + MERROR("Failed to find tx in txpool"); + return false; + } cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(id); if (!parse_and_validate_tx_from_blob(txblob, tx)) { @@ -514,10 +519,13 @@ namespace cryptonote { try { - txpool_tx_meta_t meta = m_blockchain.get_txpool_tx_meta(it->first); - meta.relayed = true; - meta.last_relayed_time = now; - m_blockchain.update_txpool_tx(it->first, meta); + txpool_tx_meta_t meta; + if (m_blockchain.get_txpool_tx_meta(it->first, meta)) + { + meta.relayed = true; + meta.last_relayed_time = now; + m_blockchain.update_txpool_tx(it->first, meta); + } } catch (const std::exception &e) { @@ -696,7 +704,11 @@ namespace cryptonote { try { - meta = m_blockchain.get_txpool_tx_meta(tx_id_hash); + if (!m_blockchain.get_txpool_tx_meta(tx_id_hash, meta)) + { + MERROR("Failed to get tx meta from txpool"); + return false; + } if (!meta.relayed) // Do not include that transaction if in restricted mode and it's not relayed continue; @@ -918,7 +930,13 @@ namespace cryptonote { for (const crypto::hash &txid: it->second) { - txpool_tx_meta_t meta = m_blockchain.get_txpool_tx_meta(txid); + txpool_tx_meta_t meta; + if (!m_blockchain.get_txpool_tx_meta(txid, meta)) + { + MERROR("Failed to find tx meta in txpool"); + // continue, not fatal + continue; + } if (!meta.double_spend_seen) { MDEBUG("Marking " << txid << " as double spending " << itk.k_image); @@ -998,7 +1016,12 @@ namespace cryptonote auto sorted_it = m_txs_by_fee_and_receive_time.begin(); while (sorted_it != m_txs_by_fee_and_receive_time.end()) { - txpool_tx_meta_t meta = m_blockchain.get_txpool_tx_meta(sorted_it->second); + txpool_tx_meta_t meta; + if (!m_blockchain.get_txpool_tx_meta(sorted_it->second, meta)) + { + MERROR(" failed to find tx meta"); + continue; + } LOG_PRINT_L2("Considering " << sorted_it->second << ", size " << meta.blob_size << ", current block size " << total_size << "/" << max_total_size << ", current coinbase " << print_money(best_coinbase)); // Can not exceed maximum block size diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index f4f24ed77..b9a3e45b4 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -3307,6 +3307,13 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args { if (!parse_subaddress_indices(local_args[0], subaddr_indices)) return true; + local_args.erase(local_args.begin()); + } + + if (local_args.size() > 0) + { + fail_msg_writer() << tr("usage: incoming_transfers [available|unavailable] [verbose] [index=<N>]"); + return true; } tools::wallet2::transfer_container transfers; @@ -4528,6 +4535,12 @@ bool simple_wallet::sweep_below(const std::vector<std::string> &args_) //---------------------------------------------------------------------------------------------------- bool simple_wallet::donate(const std::vector<std::string> &args_) { + if(m_wallet->testnet()) + { + fail_msg_writer() << tr("donations are not enabled on the testnet"); + return true; + } + std::vector<std::string> local_args = args_; if(local_args.empty() || local_args.size() > 5) { @@ -6195,6 +6208,7 @@ bool simple_wallet::export_key_images(const std::vector<std::string> &args) try { + LOCK_IDLE_SCOPE(); if (!m_wallet->export_key_images(filename)) { fail_msg_writer() << tr("failed to save file ") << filename; @@ -6227,6 +6241,7 @@ bool simple_wallet::import_key_images(const std::vector<std::string> &args) } std::string filename = args[0]; + LOCK_IDLE_SCOPE(); try { uint64_t spent = 0, unspent = 0; @@ -6258,6 +6273,7 @@ bool simple_wallet::export_outputs(const std::vector<std::string> &args) if (m_wallet->ask_password() && !get_and_verify_password()) { return true; } std::string filename = args[0]; + LOCK_IDLE_SCOPE(); try { std::vector<tools::wallet2::transfer_details> outs = m_wallet->export_outputs(); @@ -6356,6 +6372,7 @@ bool simple_wallet::import_outputs(const std::vector<std::string> &args) boost::archive::binary_iarchive ar(iss); ar >> outputs; } + LOCK_IDLE_SCOPE(); size_t n_outputs = m_wallet->import_outputs(outputs); success_msg_writer() << boost::lexical_cast<std::string>(n_outputs) << " outputs imported"; } diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 724d19efd..f36a12a1d 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -6159,7 +6159,8 @@ void wallet2::light_wallet_get_unspent_outs() add_tx_pub_key_to_extra(td.m_tx, tx_pub_key); td.m_key_image = unspent_key_image; - td.m_key_image_known = !m_watch_only; + td.m_key_image_known = !m_watch_only && !m_multisig; + td.m_key_image_partial = m_multisig; td.m_amount = o.amount; td.m_pk_index = 0; td.m_internal_output_index = o.index; @@ -6960,37 +6961,48 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below THROW_WALLET_EXCEPTION_IF(unlocked_balance(subaddr_account) == 0, error::wallet_internal_error, "No unlocked balance in the entire wallet"); - std::map<uint32_t, uint64_t> balance_per_subaddr = unlocked_balance_per_subaddress(subaddr_account); + std::map<uint32_t, std::pair<std::vector<size_t>, std::vector<size_t>>> unused_transfer_dust_indices_per_subaddr; - if (subaddr_indices.empty()) - { - // in case subaddress index wasn't specified, choose non-empty subaddress randomly (with index=0 being chosen last) - if (balance_per_subaddr.count(0) == 1 && balance_per_subaddr.size() > 1) - balance_per_subaddr.erase(0); - auto i = balance_per_subaddr.begin(); - std::advance(i, crypto::rand<size_t>() % balance_per_subaddr.size()); - subaddr_indices.insert(i->first); - } - for (uint32_t i : subaddr_indices) - LOG_PRINT_L2("Spending from subaddress index " << i); - - // gather all dust and non-dust outputs of specified subaddress + // gather all dust and non-dust outputs of specified subaddress (if any) and below specified threshold (if any) + bool fund_found = false; for (size_t i = 0; i < m_transfers.size(); ++i) { const transfer_details& td = m_transfers[i]; - if (!td.m_spent && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1) + if (!td.m_spent && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && (subaddr_indices.empty() || subaddr_indices.count(td.m_subaddr_index.minor) == 1)) { + fund_found = true; if (below == 0 || td.amount() < below) { if ((td.is_rct()) || is_valid_decomposed_amount(td.amount())) - unused_transfers_indices.push_back(i); + unused_transfer_dust_indices_per_subaddr[td.m_subaddr_index.minor].first.push_back(i); else - unused_dust_indices.push_back(i); + unused_transfer_dust_indices_per_subaddr[td.m_subaddr_index.minor].second.push_back(i); } } } + THROW_WALLET_EXCEPTION_IF(!fund_found, error::wallet_internal_error, "No unlocked balance in the specified subaddress(es)"); + THROW_WALLET_EXCEPTION_IF(unused_transfer_dust_indices_per_subaddr.empty(), error::wallet_internal_error, "The smallest amount found is not below the specified threshold"); - THROW_WALLET_EXCEPTION_IF(unused_transfers_indices.empty() && unused_dust_indices.empty(), error::not_enough_money, 0, 0, 0); // not sure if a new error class (something like 'cant_sweep_empty'?) should be introduced + if (subaddr_indices.empty()) + { + // in case subaddress index wasn't specified, choose non-empty subaddress randomly (with index=0 being chosen last) + if (unused_transfer_dust_indices_per_subaddr.count(0) == 1 && unused_transfer_dust_indices_per_subaddr.size() > 1) + unused_transfer_dust_indices_per_subaddr.erase(0); + auto i = unused_transfer_dust_indices_per_subaddr.begin(); + std::advance(i, crypto::rand<size_t>() % unused_transfer_dust_indices_per_subaddr.size()); + unused_transfers_indices = i->second.first; + unused_dust_indices = i->second.second; + LOG_PRINT_L2("Spending from subaddress index " << i->first); + } + else + { + for (const auto& p : unused_transfer_dust_indices_per_subaddr) + { + unused_transfers_indices.insert(unused_transfers_indices.end(), p.second.first.begin(), p.second.first.end()); + unused_dust_indices.insert(unused_dust_indices.end(), p.second.second.begin(), p.second.second.end()); + LOG_PRINT_L2("Spending from subaddress index " << p.first); + } + } return create_transactions_from(address, is_subaddress, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra, trusted_daemon); } diff --git a/tests/unit_tests/hardfork.cpp b/tests/unit_tests/hardfork.cpp index c235f49fd..0a472a421 100644 --- a/tests/unit_tests/hardfork.cpp +++ b/tests/unit_tests/hardfork.cpp @@ -118,7 +118,7 @@ public: virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const { return 0; } virtual bool txpool_has_tx(const crypto::hash &txid) const { return false; } virtual void remove_txpool_tx(const crypto::hash& txid) {} - virtual txpool_tx_meta_t get_txpool_tx_meta(const crypto::hash& txid) const { return txpool_tx_meta_t(); } + virtual bool get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const { return false; } virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const { return false; } virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const { return ""; } virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false, bool include_unrelayed_txes = false) const { return false; } |