aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/api/transaction_history.cpp6
-rw-r--r--src/wallet/wallet2.cpp71
-rw-r--r--src/wallet/wallet2.h39
-rwxr-xr-xsrc/wallet/wallet_rpc_server.cpp14
-rw-r--r--src/wallet/wallet_rpc_server.h2
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h2
6 files changed, 94 insertions, 40 deletions
diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp
index 59eca3dd7..8a8243047 100644
--- a/src/wallet/api/transaction_history.cpp
+++ b/src/wallet/api/transaction_history.cpp
@@ -217,10 +217,10 @@ void TransactionHistoryImpl::refresh()
// unconfirmed payments (tx pool)
- std::list<std::pair<crypto::hash, tools::wallet2::payment_details>> upayments;
+ std::list<std::pair<crypto::hash, tools::wallet2::pool_payment_details>> upayments;
m_wallet->m_wallet->get_unconfirmed_payments(upayments);
- for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = upayments.begin(); i != upayments.end(); ++i) {
- const tools::wallet2::payment_details &pd = i->second;
+ for (std::list<std::pair<crypto::hash, tools::wallet2::pool_payment_details>>::const_iterator i = upayments.begin(); i != upayments.end(); ++i) {
+ const tools::wallet2::payment_details &pd = i->second.m_pd;
std::string payment_id = string_tools::pod_to_hex(i->first);
if (payment_id.substr(16).find_first_not_of('0') == std::string::npos)
payment_id = payment_id.substr(0,16);
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index a87803206..5e747e7f6 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -444,6 +444,21 @@ std::string strjoin(const std::vector<size_t> &V, const char *sep)
return ss.str();
}
+static void emplace_or_replace(std::unordered_multimap<crypto::hash, tools::wallet2::pool_payment_details> &container,
+ const crypto::hash &key, const tools::wallet2::pool_payment_details &pd)
+{
+ auto range = container.equal_range(key);
+ for (auto i = range.first; i != range.second; ++i)
+ {
+ if (i->second.m_pd.m_tx_hash == pd.m_pd.m_tx_hash)
+ {
+ i->second = pd;
+ return;
+ }
+ }
+ container.emplace(key, pd);
+}
+
} //namespace
namespace tools
@@ -793,7 +808,7 @@ void wallet2::scan_output(const cryptonote::account_keys &keys, const cryptonote
++num_vouts_received;
}
//----------------------------------------------------------------------------------------------------
-void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool)
+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)
@@ -1163,7 +1178,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
payment.m_timestamp = ts;
payment.m_subaddr_index = i.first;
if (pool) {
- m_unconfirmed_payments.emplace(payment_id, payment);
+ emplace_or_replace(m_unconfirmed_payments, payment_id, pool_payment_details{payment, double_spend_seen});
if (0 != m_callback)
m_callback->on_unconfirmed_money_received(height, txid, tx, payment.m_amount, payment.m_subaddr_index);
}
@@ -1241,7 +1256,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry
if(b.timestamp + 60*60*24 > m_account.get_createtime() && height >= m_refresh_from_block_height)
{
TIME_MEASURE_START(miner_tx_handle_time);
- process_new_transaction(get_transaction_hash(b.miner_tx), b.miner_tx, o_indices.indices[txidx++].indices, height, b.timestamp, true, false);
+ process_new_transaction(get_transaction_hash(b.miner_tx), b.miner_tx, o_indices.indices[txidx++].indices, height, b.timestamp, true, false, false);
TIME_MEASURE_FINISH(miner_tx_handle_time);
TIME_MEASURE_START(txs_handle_time);
@@ -1252,7 +1267,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry
cryptonote::transaction tx;
bool r = parse_and_validate_tx_base_from_blob(txblob, tx);
THROW_WALLET_EXCEPTION_IF(!r, error::tx_parse_error, txblob);
- process_new_transaction(b.tx_hashes[idx], tx, o_indices.indices[txidx++].indices, height, b.timestamp, false, false);
+ process_new_transaction(b.tx_hashes[idx], tx, o_indices.indices[txidx++].indices, height, b.timestamp, false, false, false);
++idx;
}
TIME_MEASURE_FINISH(txs_handle_time);
@@ -1520,10 +1535,10 @@ void wallet2::pull_next_blocks(uint64_t start_height, uint64_t &blocks_start_hei
void wallet2::remove_obsolete_pool_txs(const std::vector<crypto::hash> &tx_hashes)
{
// remove pool txes to us that aren't in the pool anymore
- std::unordered_multimap<crypto::hash, wallet2::payment_details>::iterator uit = m_unconfirmed_payments.begin();
+ std::unordered_multimap<crypto::hash, wallet2::pool_payment_details>::iterator uit = m_unconfirmed_payments.begin();
while (uit != m_unconfirmed_payments.end())
{
- const crypto::hash &txid = uit->second.m_tx_hash;
+ const crypto::hash &txid = uit->second.m_pd.m_tx_hash;
bool found = false;
for (const auto &it2: tx_hashes)
{
@@ -1626,23 +1641,27 @@ void wallet2::update_pool_state(bool refreshed)
MDEBUG("update_pool_state done second loop");
// gather txids of new pool txes to us
- std::vector<crypto::hash> txids;
+ std::vector<std::pair<crypto::hash, bool>> txids;
for (const auto &txid: res.tx_hashes)
{
- if (m_scanned_pool_txs[0].find(txid) != m_scanned_pool_txs[0].end() || m_scanned_pool_txs[1].find(txid) != m_scanned_pool_txs[1].end())
- {
- LOG_PRINT_L2("Already seen " << txid << ", skipped");
- continue;
- }
bool txid_found_in_up = false;
for (const auto &up: m_unconfirmed_payments)
{
- if (up.second.m_tx_hash == txid)
+ if (up.second.m_pd.m_tx_hash == txid)
{
txid_found_in_up = true;
break;
}
}
+ if (m_scanned_pool_txs[0].find(txid) != m_scanned_pool_txs[0].end() || m_scanned_pool_txs[1].find(txid) != m_scanned_pool_txs[1].end())
+ {
+ // if it's for us, we want to keep track of whether we saw a double spend, so don't bail out
+ if (!txid_found_in_up)
+ {
+ LOG_PRINT_L2("Already seen " << txid << ", and not for us, skipped");
+ continue;
+ }
+ }
if (!txid_found_in_up)
{
LOG_PRINT_L1("Found new pool tx: " << txid);
@@ -1670,7 +1689,7 @@ void wallet2::update_pool_state(bool refreshed)
if (!found)
{
// not one of those we sent ourselves
- txids.push_back(txid);
+ txids.push_back({txid, false});
}
else
{
@@ -1680,6 +1699,7 @@ void wallet2::update_pool_state(bool refreshed)
else
{
LOG_PRINT_L1("Already saw that one, it's for us");
+ txids.push_back({txid, true});
}
}
@@ -1688,8 +1708,8 @@ void wallet2::update_pool_state(bool refreshed)
{
cryptonote::COMMAND_RPC_GET_TRANSACTIONS::request req;
cryptonote::COMMAND_RPC_GET_TRANSACTIONS::response res;
- for (const auto &txid: txids)
- req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
+ for (const auto &p: txids)
+ req.txs_hashes.push_back(epee::string_tools::pod_to_hex(p.first));
MDEBUG("asking for " << txids.size() << " transactions");
req.decode_as_json = false;
m_daemon_rpc_mutex.lock();
@@ -1711,10 +1731,11 @@ void wallet2::update_pool_state(bool refreshed)
{
if (cryptonote::parse_and_validate_tx_from_blob(bd, tx, tx_hash, tx_prefix_hash))
{
- const std::vector<crypto::hash>::const_iterator i = std::find(txids.begin(), txids.end(), tx_hash);
+ const std::vector<std::pair<crypto::hash, bool>>::const_iterator i = std::find_if(txids.begin(), txids.end(),
+ [tx_hash](const std::pair<crypto::hash, bool> &e) { return e.first == tx_hash; });
if (i != txids.end())
{
- process_new_transaction(tx_hash, tx, std::vector<uint64_t>(), 0, time(NULL), false, true);
+ process_new_transaction(tx_hash, tx, std::vector<uint64_t>(), 0, time(NULL), false, true, tx_entry.double_spend_seen);
m_scanned_pool_txs[0].insert(tx_hash);
if (m_scanned_pool_txs[0].size() > 5000)
{
@@ -3073,11 +3094,11 @@ void wallet2::get_unconfirmed_payments_out(std::list<std::pair<crypto::hash,wall
}
}
//----------------------------------------------------------------------------------------------------
-void wallet2::get_unconfirmed_payments(std::list<std::pair<crypto::hash,wallet2::payment_details>>& unconfirmed_payments, const boost::optional<uint32_t>& subaddr_account, const std::set<uint32_t>& subaddr_indices) const
+void wallet2::get_unconfirmed_payments(std::list<std::pair<crypto::hash,wallet2::pool_payment_details>>& unconfirmed_payments, const boost::optional<uint32_t>& subaddr_account, const std::set<uint32_t>& subaddr_indices) const
{
for (auto i = m_unconfirmed_payments.begin(); i != m_unconfirmed_payments.end(); ++i) {
- if ((!subaddr_account || *subaddr_account == i->second.m_subaddr_index.major) &&
- (subaddr_indices.empty() || subaddr_indices.count(i->second.m_subaddr_index.minor) == 1))
+ if ((!subaddr_account || *subaddr_account == i->second.m_pd.m_subaddr_index.major) &&
+ (subaddr_indices.empty() || subaddr_indices.count(i->second.m_pd.m_subaddr_index.minor) == 1))
unconfirmed_payments.push_back(*i);
}
}
@@ -5129,7 +5150,7 @@ void wallet2::light_wallet_get_address_txs()
payments_txs.push_back(p.second.m_tx_hash);
std::vector<crypto::hash> unconfirmed_payments_txs;
for(const auto &up: m_unconfirmed_payments)
- unconfirmed_payments_txs.push_back(up.second.m_tx_hash);
+ unconfirmed_payments_txs.push_back(up.second.m_pd.m_tx_hash);
// for balance calculation
uint64_t wallet_total_sent = 0;
@@ -5195,7 +5216,11 @@ void wallet2::light_wallet_get_address_txs()
if (t.mempool) {
if (std::find(unconfirmed_payments_txs.begin(), unconfirmed_payments_txs.end(), tx_hash) == unconfirmed_payments_txs.end()) {
pool_txs.push_back(tx_hash);
- m_unconfirmed_payments.emplace(tx_hash, payment);
+ // assume false as we don't get that info from the light wallet server
+ crypto::hash payment_id;
+ THROW_WALLET_EXCEPTION_IF(!epee::string_tools::hex_to_pod(t.payment_id, payment_id),
+ error::wallet_internal_error, "Failed to parse payment id");
+ emplace_or_replace(m_unconfirmed_payments, payment_id, pool_payment_details{payment, false});
if (0 != m_callback) {
m_callback->on_lw_unconfirmed_money_received(t.height, payment.m_tx_hash, payment.m_amount);
}
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index f1e12a700..ba2fc567d 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -244,6 +244,12 @@ namespace tools
bool m_incoming;
};
+ struct pool_payment_details
+ {
+ payment_details m_pd;
+ bool m_double_spend_seen;
+ };
+
struct unconfirmed_transfer_details
{
cryptonote::transaction_prefix m_tx;
@@ -530,7 +536,7 @@ namespace tools
void get_payments_out(std::list<std::pair<crypto::hash,wallet2::confirmed_transfer_details>>& confirmed_payments,
uint64_t min_height, uint64_t max_height = (uint64_t)-1, const boost::optional<uint32_t>& subaddr_account = boost::none, const std::set<uint32_t>& subaddr_indices = {}) const;
void get_unconfirmed_payments_out(std::list<std::pair<crypto::hash,wallet2::unconfirmed_transfer_details>>& unconfirmed_payments, const boost::optional<uint32_t>& subaddr_account = boost::none, const std::set<uint32_t>& subaddr_indices = {}) const;
- void get_unconfirmed_payments(std::list<std::pair<crypto::hash,wallet2::payment_details>>& unconfirmed_payments, const boost::optional<uint32_t>& subaddr_account = boost::none, const std::set<uint32_t>& subaddr_indices = {}) const;
+ void get_unconfirmed_payments(std::list<std::pair<crypto::hash,wallet2::pool_payment_details>>& unconfirmed_payments, const boost::optional<uint32_t>& subaddr_account = boost::none, const std::set<uint32_t>& subaddr_indices = {}) const;
uint64_t get_blockchain_current_height() const { return m_local_bc_height; }
void rescan_spent();
@@ -585,7 +591,7 @@ namespace tools
std::unordered_map<crypto::hash, payment_details> m;
a & m;
for (std::unordered_map<crypto::hash, payment_details>::const_iterator i = m.begin(); i != m.end(); ++i)
- m_unconfirmed_payments.insert(*i);
+ m_unconfirmed_payments.insert(std::make_pair(i->first, pool_payment_details{i->second, false}));
}
if(ver < 14)
return;
@@ -607,7 +613,15 @@ namespace tools
a & m_address_book;
if(ver < 17)
return;
- a & m_unconfirmed_payments;
+ if (ver < 21)
+ {
+ // we're loading an old version, where m_unconfirmed_payments payload was payment_details
+ std::unordered_map<crypto::hash, payment_details> m;
+ a & m;
+ for (const auto &i: m)
+ m_unconfirmed_payments.insert(std::make_pair(i.first, pool_payment_details{i.second, false}));
+ return;
+ }
if(ver < 18)
return;
a & m_scanned_pool_txs[0];
@@ -621,6 +635,9 @@ namespace tools
if(ver < 21)
return;
a & m_attributes;
+ if(ver < 22)
+ return;
+ a & m_unconfirmed_payments;
}
/*!
@@ -797,7 +814,7 @@ namespace tools
* \param password Password of wallet file
*/
bool load_keys(const std::string& keys_file_name, const std::string& password);
- void 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);
+ void 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);
void process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const crypto::hash& bl_id, uint64_t height, const cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::block_output_indices &o_indices);
void detach_blockchain(uint64_t height);
void get_short_chain_history(std::list<crypto::hash>& ids) const;
@@ -846,7 +863,7 @@ namespace tools
std::atomic<uint64_t> m_local_bc_height; //temporary workaround
std::unordered_map<crypto::hash, unconfirmed_transfer_details> m_unconfirmed_txs;
std::unordered_map<crypto::hash, confirmed_transfer_details> m_confirmed_txs;
- std::unordered_multimap<crypto::hash, payment_details> m_unconfirmed_payments;
+ std::unordered_multimap<crypto::hash, pool_payment_details> m_unconfirmed_payments;
std::unordered_map<crypto::hash, crypto::secret_key> m_tx_keys;
cryptonote::checkpoints m_checkpoints;
std::unordered_map<crypto::hash, std::vector<crypto::secret_key>> m_additional_tx_keys;
@@ -908,9 +925,10 @@ namespace tools
std::unordered_map<crypto::public_key, std::map<uint64_t, crypto::key_image> > m_key_image_cache;
};
}
-BOOST_CLASS_VERSION(tools::wallet2, 21)
+BOOST_CLASS_VERSION(tools::wallet2, 22)
BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 8)
BOOST_CLASS_VERSION(tools::wallet2::payment_details, 2)
+BOOST_CLASS_VERSION(tools::wallet2::pool_payment_details, 1)
BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 7)
BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 5)
BOOST_CLASS_VERSION(tools::wallet2::address_book_row, 17)
@@ -1137,7 +1155,14 @@ namespace boost
}
a & x.m_subaddr_index;
}
-
+
+ template <class Archive>
+ inline void serialize(Archive& a, tools::wallet2::pool_payment_details& x, const boost::serialization::version_type ver)
+ {
+ a & x.m_pd;
+ a & x.m_double_spend_seen;
+ }
+
template <class Archive>
inline void serialize(Archive& a, tools::wallet2::address_book_row& x, const boost::serialization::version_type ver)
{
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 9e6a97bdc..5dbf30419 100755
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -299,8 +299,9 @@ namespace tools
entry.subaddr_index = { pd.m_subaddr_account, 0 };
}
//------------------------------------------------------------------------------------------------------------------------------
- void wallet_rpc_server::fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &payment_id, const tools::wallet2::payment_details &pd)
+ void wallet_rpc_server::fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &payment_id, const tools::wallet2::pool_payment_details &ppd)
{
+ const tools::wallet2::payment_details &pd = ppd.m_pd;
entry.txid = string_tools::pod_to_hex(pd.m_tx_hash);
entry.payment_id = string_tools::pod_to_hex(payment_id);
if (entry.payment_id.substr(16).find_first_not_of('0') == std::string::npos)
@@ -311,6 +312,7 @@ namespace tools
entry.unlock_time = pd.m_unlock_time;
entry.fee = 0; // TODO
entry.note = m_wallet->get_tx_note(pd.m_tx_hash);
+ entry.double_spend_seen = ppd.m_double_spend_seen;
entry.type = "pool";
entry.subaddr_index = pd.m_subaddr_index;
}
@@ -1357,9 +1359,9 @@ namespace tools
{
m_wallet->update_pool_state();
- std::list<std::pair<crypto::hash, tools::wallet2::payment_details>> payments;
+ std::list<std::pair<crypto::hash, tools::wallet2::pool_payment_details>> payments;
m_wallet->get_unconfirmed_payments(payments, req.account_index, req.subaddr_indices);
- for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) {
+ for (std::list<std::pair<crypto::hash, tools::wallet2::pool_payment_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) {
res.pool.push_back(wallet_rpc::transfer_entry());
fill_transfer_entry(res.pool.back(), i->first, i->second);
}
@@ -1430,10 +1432,10 @@ namespace tools
m_wallet->update_pool_state();
- std::list<std::pair<crypto::hash, tools::wallet2::payment_details>> pool_payments;
+ std::list<std::pair<crypto::hash, tools::wallet2::pool_payment_details>> pool_payments;
m_wallet->get_unconfirmed_payments(pool_payments);
- for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = pool_payments.begin(); i != pool_payments.end(); ++i) {
- if (i->second.m_tx_hash == txid)
+ for (std::list<std::pair<crypto::hash, tools::wallet2::pool_payment_details>>::const_iterator i = pool_payments.begin(); i != pool_payments.end(); ++i) {
+ if (i->second.m_pd.m_tx_hash == txid)
{
fill_transfer_entry(res.transfer, i->first, i->second);
return true;
diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h
index b38726cb7..a2677ef1b 100644
--- a/src/wallet/wallet_rpc_server.h
+++ b/src/wallet/wallet_rpc_server.h
@@ -163,7 +163,7 @@ namespace tools
void fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &txid, const crypto::hash &payment_id, const tools::wallet2::payment_details &pd);
void fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &txid, const tools::wallet2::confirmed_transfer_details &pd);
void fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &txid, const tools::wallet2::unconfirmed_transfer_details &pd);
- void fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &payment_id, const tools::wallet2::payment_details &pd);
+ void fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &payment_id, const tools::wallet2::pool_payment_details &pd);
bool not_open(epee::json_rpc::error& er);
uint64_t adjust_mixin(uint64_t mixin);
void handle_rpc_exception(const std::exception_ptr& e, epee::json_rpc::error& er, int default_error_code);
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index ffc2e2d49..06f2456c3 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -794,6 +794,7 @@ namespace wallet_rpc
std::string type;
uint64_t unlock_time;
cryptonote::subaddress_index subaddr_index;
+ bool double_spend_seen;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(txid);
@@ -807,6 +808,7 @@ namespace wallet_rpc
KV_SERIALIZE(type);
KV_SERIALIZE(unlock_time)
KV_SERIALIZE(subaddr_index);
+ KV_SERIALIZE(double_spend_seen)
END_KV_SERIALIZE_MAP()
};