diff options
Diffstat (limited to 'src/wallet/wallet2.cpp')
-rw-r--r-- | src/wallet/wallet2.cpp | 105 |
1 files changed, 95 insertions, 10 deletions
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 8ecfdeca2..6a622d953 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1038,10 +1038,15 @@ uint64_t gamma_picker::pick() return first_rct + crypto::rand_idx(n_rct); }; +boost::mutex wallet_keys_unlocker::lockers_lock; +unsigned int wallet_keys_unlocker::lockers = 0; wallet_keys_unlocker::wallet_keys_unlocker(wallet2 &w, const boost::optional<tools::password_container> &password): w(w), locked(password != boost::none) { + boost::lock_guard<boost::mutex> lock(lockers_lock); + if (lockers++ > 0) + locked = false; if (!locked || w.is_unattended() || w.ask_password() != tools::wallet2::AskPasswordToDecrypt || w.watch_only()) { locked = false; @@ -1056,6 +1061,9 @@ wallet_keys_unlocker::wallet_keys_unlocker(wallet2 &w, bool locked, const epee:: w(w), locked(locked) { + boost::lock_guard<boost::mutex> lock(lockers_lock); + if (lockers++ > 0) + locked = false; if (!locked) return; w.generate_chacha_key_from_password(password, key); @@ -1064,9 +1072,19 @@ wallet_keys_unlocker::wallet_keys_unlocker(wallet2 &w, bool locked, const epee:: wallet_keys_unlocker::~wallet_keys_unlocker() { - if (!locked) - return; - try { w.encrypt_keys(key); } + try + { + boost::lock_guard<boost::mutex> lock(lockers_lock); + if (lockers == 0) + { + MERROR("There are no lockers in wallet_keys_unlocker dtor"); + return; + } + --lockers; + if (!locked) + return; + w.encrypt_keys(key); + } catch (...) { MERROR("Failed to re-encrypt wallet keys"); @@ -1824,7 +1842,11 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote // (that is, the prunable stuff may or may not be included) if (!miner_tx && !pool) process_unconfirmed(txid, tx, height); - std::unordered_map<cryptonote::subaddress_index, uint64_t> tx_money_got_in_outs; // per receiving subaddress index + + // per receiving subaddress index + std::unordered_map<cryptonote::subaddress_index, uint64_t> tx_money_got_in_outs; + std::unordered_map<cryptonote::subaddress_index, amounts_container> tx_amounts_individual_outs; + crypto::public_key tx_pub_key = null_pkey; bool notify = false; @@ -1953,6 +1975,10 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote { hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys.data, derivation, additional_derivations); scan_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool); + if (!tx_scan_info[i].error) + { + tx_amounts_individual_outs[tx_scan_info[i].received->index].push_back(tx_scan_info[i].money_transfered); + } } } } @@ -1976,6 +2002,10 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote { hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys.data, derivation, additional_derivations); scan_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool); + if (!tx_scan_info[i].error) + { + tx_amounts_individual_outs[tx_scan_info[i].received->index].push_back(tx_scan_info[i].money_transfered); + } } } } @@ -1992,6 +2022,10 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote hwdev.set_mode(hw::device::NONE); hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys.data, derivation, additional_derivations); scan_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool); + if (!tx_scan_info[i].error) + { + tx_amounts_individual_outs[tx_scan_info[i].received->index].push_back(tx_scan_info[i].money_transfered); + } } } } @@ -2100,6 +2134,12 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote THROW_WALLET_EXCEPTION_IF(tx_money_got_in_outs[tx_scan_info[o].received->index] < tx_scan_info[o].amount, error::wallet_internal_error, "Unexpected values of new and old outputs"); tx_money_got_in_outs[tx_scan_info[o].received->index] -= tx_scan_info[o].amount; + + amounts_container& tx_amounts_this_out = tx_amounts_individual_outs[tx_scan_info[o].received->index]; // Only for readability on the following lines + auto amount_iterator = std::find(tx_amounts_this_out.begin(), tx_amounts_this_out.end(), tx_scan_info[o].amount); + THROW_WALLET_EXCEPTION_IF(amount_iterator == tx_amounts_this_out.end(), + error::wallet_internal_error, "Unexpected values of new and old outputs"); + tx_amounts_this_out.erase(amount_iterator); } else { @@ -2165,6 +2205,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote } } + THROW_WALLET_EXCEPTION_IF(tx_money_got_in_outs.size() != tx_amounts_individual_outs.size(), error::wallet_internal_error, "Inconsistent size of output arrays"); + uint64_t tx_money_spent_in_ins = 0; // The line below is equivalent to "boost::optional<uint32_t> subaddr_account;", but avoids the GCC warning: ‘*((void*)& subaddr_account +4)’ may be used uninitialized in this function // It's a GCC bug with boost::optional, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47679 @@ -2268,6 +2310,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote if (subaddr_account && i->first.major == *subaddr_account) { sub_change += i->second; + tx_amounts_individual_outs.erase(i->first); i = tx_money_got_in_outs.erase(i); } else @@ -2345,6 +2388,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote payment.m_tx_hash = txid; payment.m_fee = fee; payment.m_amount = i.second; + payment.m_amounts = tx_amounts_individual_outs[i.first]; payment.m_block_height = height; payment.m_unlock_time = tx.unlock_time; payment.m_timestamp = ts; @@ -3133,11 +3177,12 @@ void wallet2::fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, } -bool wallet2::add_address_book_row(const cryptonote::account_public_address &address, const crypto::hash &payment_id, const std::string &description, bool is_subaddress) +bool wallet2::add_address_book_row(const cryptonote::account_public_address &address, const crypto::hash8 *payment_id, const std::string &description, bool is_subaddress) { wallet2::address_book_row a; a.m_address = address; - a.m_payment_id = payment_id; + a.m_has_payment_id = !!payment_id; + a.m_payment_id = payment_id ? *payment_id : crypto::null_hash8; a.m_description = description; a.m_is_subaddress = is_subaddress; @@ -3148,11 +3193,12 @@ bool wallet2::add_address_book_row(const cryptonote::account_public_address &add return false; } -bool wallet2::set_address_book_row(size_t row_id, const cryptonote::account_public_address &address, const crypto::hash &payment_id, const std::string &description, bool is_subaddress) +bool wallet2::set_address_book_row(size_t row_id, const cryptonote::account_public_address &address, const crypto::hash8 *payment_id, const std::string &description, bool is_subaddress) { wallet2::address_book_row a; a.m_address = address; - a.m_payment_id = payment_id; + a.m_has_payment_id = !!payment_id; + a.m_payment_id = payment_id ? *payment_id : crypto::null_hash8; a.m_description = description; a.m_is_subaddress = is_subaddress; @@ -5394,6 +5440,7 @@ bool wallet2::check_connection(uint32_t *version, bool *ssl, uint32_t timeout) void wallet2::set_offline(bool offline) { m_offline = offline; + m_node_rpc_proxy.set_offline(offline); m_http_client.set_auto_connect(!offline); if (offline) { @@ -7555,6 +7602,8 @@ bool wallet2::is_output_blackballed(const std::pair<uint64_t, uint64_t> &output) bool wallet2::lock_keys_file() { + if (m_wallet_file.empty()) + return true; if (m_keys_file_locker) { MDEBUG(m_keys_file << " is already locked."); @@ -7566,6 +7615,8 @@ bool wallet2::lock_keys_file() bool wallet2::unlock_keys_file() { + if (m_wallet_file.empty()) + return true; if (!m_keys_file_locker) { MDEBUG(m_keys_file << " is already unlocked."); @@ -7577,6 +7628,8 @@ bool wallet2::unlock_keys_file() bool wallet2::is_keys_file_locked() const { + if (m_wallet_file.empty()) + return false; return m_keys_file_locker->locked(); } @@ -11802,13 +11855,27 @@ void wallet2::set_account_tag_description(const std::string& tag, const std::str m_account_tags.first[tag] = description; } -std::string wallet2::sign(const std::string &data) const +std::string wallet2::sign(const std::string &data, cryptonote::subaddress_index index) const { crypto::hash hash; crypto::cn_fast_hash(data.data(), data.size(), hash); const cryptonote::account_keys &keys = m_account.get_keys(); crypto::signature signature; - crypto::generate_signature(hash, keys.m_account_address.m_spend_public_key, keys.m_spend_secret_key, signature); + crypto::secret_key skey; + crypto::public_key pkey; + if (index.is_zero()) + { + skey = keys.m_spend_secret_key; + pkey = keys.m_account_address.m_spend_public_key; + } + else + { + skey = keys.m_spend_secret_key; + crypto::secret_key m = m_account.get_device().get_subaddress_secret_key(keys.m_view_secret_key, index); + sc_add((unsigned char*)&skey, (unsigned char*)&m, (unsigned char*)&skey); + secret_key_to_public_key(skey, pkey); + } + crypto::generate_signature(hash, pkey, skey, signature); return std::string("SigV1") + tools::base58::encode(std::string((const char *)&signature, sizeof(signature))); } @@ -13601,4 +13668,22 @@ std::vector<cryptonote::public_node> wallet2::get_public_nodes(bool white_only) std::copy(res.gray.begin(), res.gray.end(), std::back_inserter(nodes)); return nodes; } +//---------------------------------------------------------------------------------------------------- +std::pair<size_t, uint64_t> wallet2::estimate_tx_size_and_weight(bool use_rct, int n_inputs, int ring_size, int n_outputs, size_t extra_size) +{ + THROW_WALLET_EXCEPTION_IF(n_inputs <= 0, tools::error::wallet_internal_error, "Invalid n_inputs"); + THROW_WALLET_EXCEPTION_IF(n_outputs < 0, tools::error::wallet_internal_error, "Invalid n_outputs"); + THROW_WALLET_EXCEPTION_IF(ring_size < 0, tools::error::wallet_internal_error, "Invalid ring size"); + + if (ring_size == 0) + ring_size = get_min_ring_size(); + if (n_outputs == 1) + n_outputs = 2; // extra dummy output + + const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0); + size_t size = estimate_tx_size(use_rct, n_inputs, ring_size - 1, n_outputs, extra_size, bulletproof); + uint64_t weight = estimate_tx_weight(use_rct, n_inputs, ring_size - 1, n_outputs, extra_size, bulletproof); + return std::make_pair(size, weight); +} +//---------------------------------------------------------------------------------------------------- } |