aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmake/FindReadline.cmake47
-rw-r--r--src/blockchain_db/blockchain_db.h5
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp8
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h2
-rw-r--r--src/cryptonote_core/blockchain.cpp4
-rw-r--r--src/cryptonote_core/blockchain.h2
-rw-r--r--src/cryptonote_core/tx_pool.cpp39
-rw-r--r--src/simplewallet/simplewallet.cpp17
-rw-r--r--src/wallet/wallet2.cpp50
-rw-r--r--tests/unit_tests/hardfork.cpp2
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; }