From 00bf0b5ef061887f1e41e65b6ca60cfb52335147 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Mon, 1 Oct 2018 14:46:32 +0000 Subject: [PATCH 01/27] wallet_rpc_server: include all transfer records for a txid Since subaddresses were added, a tx can now create more than one payment --- src/wallet/wallet_rpc_server.cpp | 22 +++++++++++++------- src/wallet/wallet_rpc_server_commands_defs.h | 13 ++++++++++++ 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 21916d0ae..64cb9da61 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -1938,8 +1938,8 @@ namespace tools for (std::list>::const_iterator i = payments.begin(); i != payments.end(); ++i) { if (i->second.m_tx_hash == txid) { - fill_transfer_entry(res.transfer, i->second.m_tx_hash, i->first, i->second); - return true; + res.transfers.resize(res.transfers.size() + 1); + fill_transfer_entry(res.transfers.back(), i->second.m_tx_hash, i->first, i->second); } } @@ -1948,8 +1948,8 @@ namespace tools for (std::list>::const_iterator i = payments_out.begin(); i != payments_out.end(); ++i) { if (i->first == txid) { - fill_transfer_entry(res.transfer, i->first, i->second); - return true; + res.transfers.resize(res.transfers.size() + 1); + fill_transfer_entry(res.transfers.back(), i->first, i->second); } } @@ -1958,8 +1958,8 @@ namespace tools for (std::list>::const_iterator i = upayments.begin(); i != upayments.end(); ++i) { if (i->first == txid) { - fill_transfer_entry(res.transfer, i->first, i->second); - return true; + res.transfers.resize(res.transfers.size() + 1); + fill_transfer_entry(res.transfers.back(), i->first, i->second); } } @@ -1970,11 +1970,17 @@ namespace tools for (std::list>::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; + res.transfers.resize(res.transfers.size() + 1); + fill_transfer_entry(res.transfers.back(), i->first, i->second); } } + if (!res.transfers.empty()) + { + res.transfer = res.transfers.front(); // backward compat + return true; + } + er.code = WALLET_RPC_ERROR_CODE_WRONG_TXID; er.message = "Transaction not found."; return false; diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index a0f43c9b9..e12a5f415 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -39,6 +39,17 @@ #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "wallet.rpc" +// When making *any* change here, bump minor +// If the change is incompatible, then bump major and set minor to 0 +// This ensures WALLET_RPC_VERSION always increases, that every change +// has its own version, and that clients can just test major to see +// whether they can talk to a given wallet without having to know in +// advance which version they will stop working with +// Don't go over 32767 for any of these +#define WALLET_RPC_VERSION_MAJOR 1 +#define WALLET_RPC_VERSION_MINOR 4 +#define MAKE_WALLET_RPC_VERSION(major,minor) (((major)<<16)|(minor)) +#define WALLET_RPC_VERSION MAKE_WALLET_RPC_VERSION(WALLET_RPC_VERSION_MAJOR, WALLET_RPC_VERSION_MINOR) namespace tools { namespace wallet_rpc @@ -1311,9 +1322,11 @@ namespace wallet_rpc struct response { transfer_entry transfer; + std::list transfers; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(transfer); + KV_SERIALIZE(transfers); END_KV_SERIALIZE_MAP() }; }; From 44e0f9eebff4154e7fbcc1337b51e04653d5484d Mon Sep 17 00:00:00 2001 From: doy-lee Date: Wed, 26 Sep 2018 12:38:39 +0000 Subject: [PATCH 02/27] wallet2: clear found out for every tx key Avoids triggering the sanity check --- src/wallet/wallet2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index a6f81322e..ae22917e8 100755 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1105,7 +1105,6 @@ 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::vector outs; std::unordered_map tx_money_got_in_outs; // per receiving subaddress index crypto::public_key tx_pub_key = null_pkey; @@ -1123,6 +1122,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote uint64_t total_received_1 = 0; while (!tx.vout.empty()) { + std::vector outs; // if tx.vout is not empty, we loop through all tx pubkeys tx_extra_pub_key pub_key_field; From 2998b929d58e879462ead297bd285a0b3c89f70d Mon Sep 17 00:00:00 2001 From: stoffu Date: Mon, 15 Oct 2018 11:57:02 +0900 Subject: [PATCH 03/27] tx_pool: store hex string instead of raw binary to tx_blob of get_transaction_pool RPC Inspired by https://github.com/masari-project/masari/issues/93 --- src/cryptonote_core/tx_pool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 684a6b363..036cb7d33 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -746,7 +746,7 @@ namespace cryptonote m_blockchain.for_all_txpool_txes([&tx_infos, key_image_infos, include_sensitive_data](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){ tx_info txi; txi.id_hash = epee::string_tools::pod_to_hex(txid); - txi.tx_blob = *bd; + txi.tx_blob = epee::string_tools::buff_to_hex_nodelimer(*bd); transaction tx; if (!parse_and_validate_tx_from_blob(*bd, tx)) { From a09d5ea211253e9bf8e1b9f3ef9321881e7ed4eb Mon Sep 17 00:00:00 2001 From: Jorropo Date: Wed, 25 Jul 2018 10:16:01 +0200 Subject: [PATCH 04/27] [monerod] Added blocks remaining count during syncronisation. And percent if usefull (% < 99) --- .../cryptonote_protocol_handler.inl | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index 6e7240b57..e970afcde 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -1167,8 +1167,20 @@ skip: + " blocks/sec), " + std::to_string(m_block_queue.get_data_size() / 1048576.f) + " MB queued"; if (ELPP->vRegistry()->allowed(el::Level::Debug, "sync-info")) timing_message += std::string(": ") + m_block_queue.get_overview(); - MGINFO_YELLOW(context << " Synced " << m_core.get_current_blockchain_height() << "/" << m_core.get_target_blockchain_height() + if(m_core.get_target_blockchain_height() == 0){ + MGINFO_YELLOW(context << " Synced " << m_core.get_current_blockchain_height() << "/" << m_core.get_target_blockchain_height() << timing_message); + } else { + const int completition_percent = (m_core.get_current_blockchain_height() * 100 / m_core.get_target_blockchain_height()); + if(completition_percent < 99) {//printing completion percent only if % is < of 99 cause for 99 >= this is useless + MGINFO_YELLOW(context << " Synced " << m_core.get_current_blockchain_height() << "/" << m_core.get_target_blockchain_height() + << " (" << completition_percent << "% " << (m_core.get_target_blockchain_height() - m_core.get_current_blockchain_height()) + << " blocks remaining)" << timing_message); + } else { + MGINFO_YELLOW(context << " Synced " << m_core.get_current_blockchain_height() << "/" << m_core.get_target_blockchain_height() + << timing_message); + } + } } } } @@ -1752,3 +1764,4 @@ skip: m_core.stop(); } } // namespace + From 83e5d6a82959befa0ca74f70ca3a8a929d520799 Mon Sep 17 00:00:00 2001 From: stoffu Date: Mon, 23 Jul 2018 23:45:11 +0900 Subject: [PATCH 05/27] wallet-rpc: add get_address_index command --- src/wallet/wallet2.cpp | 8 ++++++++ src/wallet/wallet2.h | 1 + src/wallet/wallet_rpc_server.cpp | 21 ++++++++++++++++++++ src/wallet/wallet_rpc_server.h | 2 ++ src/wallet/wallet_rpc_server_commands_defs.h | 19 ++++++++++++++++++ 5 files changed, 51 insertions(+) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index ae22917e8..35bbde9d5 100755 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -887,6 +887,14 @@ cryptonote::account_public_address wallet2::get_subaddress(const cryptonote::sub return hwdev.get_subaddress(m_account.get_keys(), index); } //---------------------------------------------------------------------------------------------------- +boost::optional wallet2::get_subaddress_index(const cryptonote::account_public_address& address) const +{ + auto index = m_subaddresses.find(address.m_spend_public_key); + if (index == m_subaddresses.end()) + return boost::none; + return index->second; +} +//---------------------------------------------------------------------------------------------------- crypto::public_key wallet2::get_subaddress_spend_public_key(const cryptonote::subaddress_index& index) const { hw::device &hwdev = m_account.get_device(); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 4488dbb2a..af4c9ad8e 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -624,6 +624,7 @@ namespace tools // Subaddress scheme cryptonote::account_public_address get_subaddress(const cryptonote::subaddress_index& index) const; cryptonote::account_public_address get_address() const { return get_subaddress({0,0}); } + boost::optional get_subaddress_index(const cryptonote::account_public_address& address) const; crypto::public_key get_subaddress_spend_public_key(const cryptonote::subaddress_index& index) const; std::vector get_subaddress_spend_public_keys(uint32_t account, uint32_t begin, uint32_t end) const; std::string get_subaddress_as_str(const cryptonote::subaddress_index& index) const; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 64cb9da61..6ee6dc279 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -397,6 +397,27 @@ namespace tools return true; } //------------------------------------------------------------------------------------------------------------------------------ + bool wallet_rpc_server::on_getaddress_index(const wallet_rpc::COMMAND_RPC_GET_ADDRESS_INDEX::request& req, wallet_rpc::COMMAND_RPC_GET_ADDRESS_INDEX::response& res, epee::json_rpc::error& er) + { + if (!m_wallet) return not_open(er); + cryptonote::address_parse_info info; + if(!get_account_address_from_str(info, m_wallet->nettype(), req.address)) + { + er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS; + er.message = "Invalid address"; + return false; + } + auto index = m_wallet->get_subaddress_index(info.address); + if (!index) + { + er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS; + er.message = "Address doesn't belong to the wallet"; + return false; + } + res.index = *index; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::on_create_address(const wallet_rpc::COMMAND_RPC_CREATE_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_CREATE_ADDRESS::response& res, epee::json_rpc::error& er) { if (!m_wallet) return not_open(er); diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h index 2ec53cc80..a68e12d97 100644 --- a/src/wallet/wallet_rpc_server.h +++ b/src/wallet/wallet_rpc_server.h @@ -69,6 +69,7 @@ namespace tools BEGIN_JSON_RPC_MAP("/json_rpc") MAP_JON_RPC_WE("get_balance", on_getbalance, wallet_rpc::COMMAND_RPC_GET_BALANCE) MAP_JON_RPC_WE("get_address", on_getaddress, wallet_rpc::COMMAND_RPC_GET_ADDRESS) + MAP_JON_RPC_WE("get_address_index", on_getaddress_index, wallet_rpc::COMMAND_RPC_GET_ADDRESS_INDEX) MAP_JON_RPC_WE("getbalance", on_getbalance, wallet_rpc::COMMAND_RPC_GET_BALANCE) MAP_JON_RPC_WE("getaddress", on_getaddress, wallet_rpc::COMMAND_RPC_GET_ADDRESS) MAP_JON_RPC_WE("create_address", on_create_address, wallet_rpc::COMMAND_RPC_CREATE_ADDRESS) @@ -141,6 +142,7 @@ namespace tools //json_rpc bool on_getbalance(const wallet_rpc::COMMAND_RPC_GET_BALANCE::request& req, wallet_rpc::COMMAND_RPC_GET_BALANCE::response& res, epee::json_rpc::error& er); bool on_getaddress(const wallet_rpc::COMMAND_RPC_GET_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_GET_ADDRESS::response& res, epee::json_rpc::error& er); + bool on_getaddress_index(const wallet_rpc::COMMAND_RPC_GET_ADDRESS_INDEX::request& req, wallet_rpc::COMMAND_RPC_GET_ADDRESS_INDEX::response& res, epee::json_rpc::error& er); bool on_create_address(const wallet_rpc::COMMAND_RPC_CREATE_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_CREATE_ADDRESS::response& res, epee::json_rpc::error& er); bool on_label_address(const wallet_rpc::COMMAND_RPC_LABEL_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_LABEL_ADDRESS::response& res, epee::json_rpc::error& er); bool on_get_accounts(const wallet_rpc::COMMAND_RPC_GET_ACCOUNTS::request& req, wallet_rpc::COMMAND_RPC_GET_ACCOUNTS::response& res, epee::json_rpc::error& er); diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index e12a5f415..c61645826 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -141,6 +141,25 @@ namespace wallet_rpc }; }; + struct COMMAND_RPC_GET_ADDRESS_INDEX + { + struct request + { + std::string address; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(address) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + cryptonote::subaddress_index index; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(index) + END_KV_SERIALIZE_MAP() + }; + }; + struct COMMAND_RPC_CREATE_ADDRESS { struct request From 7ba6d691965e9a5c675c008aafca9b21b9a57337 Mon Sep 17 00:00:00 2001 From: stoffu Date: Mon, 23 Jul 2018 23:58:31 +0900 Subject: [PATCH 06/27] wallet-rpc: filter getbalance response by address index --- src/wallet/wallet_rpc_server.cpp | 14 ++++++++++---- src/wallet/wallet_rpc_server_commands_defs.h | 2 ++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 6ee6dc279..1b3bdf84d 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -336,14 +336,20 @@ namespace tools std::map unlocked_balance_per_subaddress = m_wallet->unlocked_balance_per_subaddress(req.account_index); std::vector transfers; m_wallet->get_transfers(transfers); - for (const auto& i : balance_per_subaddress) + std::set address_indices = req.address_indices; + if (address_indices.empty()) + { + for (const auto& i : balance_per_subaddress) + address_indices.insert(i.first); + } + for (uint32_t i : address_indices) { wallet_rpc::COMMAND_RPC_GET_BALANCE::per_subaddress_info info; - info.address_index = i.first; + info.address_index = i; cryptonote::subaddress_index index = {req.account_index, info.address_index}; info.address = m_wallet->get_subaddress_as_str(index); - info.balance = i.second; - info.unlocked_balance = unlocked_balance_per_subaddress[i.first]; + info.balance = balance_per_subaddress[i]; + info.unlocked_balance = unlocked_balance_per_subaddress[i]; info.label = m_wallet->get_subaddress_label(index); info.num_unspent_outputs = std::count_if(transfers.begin(), transfers.end(), [&](const tools::wallet2::transfer_details& td) { return !td.m_spent && td.m_subaddr_index == index; }); res.per_subaddress.push_back(info); diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index c61645826..f264829ad 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -62,8 +62,10 @@ namespace wallet_rpc struct request { uint32_t account_index; + std::set address_indices; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(account_index) + KV_SERIALIZE(address_indices) END_KV_SERIALIZE_MAP() }; From ee45ef2c9ec19f0179a5e14b135e5cb569436824 Mon Sep 17 00:00:00 2001 From: stoffu Date: Tue, 24 Jul 2018 13:32:58 +0900 Subject: [PATCH 07/27] simplewallet.unspent_outputs: fix wrong logic for parsing --- src/simplewallet/simplewallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index bf76f3ffa..b7800d9b5 100755 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -6167,7 +6167,7 @@ bool simple_wallet::unspent_outputs(const std::vector &args_) auto local_args = args_; std::set subaddr_indices; - if (local_args.size() > 0 && local_args[0].substr(0, 6) != "index=") + if (local_args.size() > 0 && local_args[0].substr(0, 6) == "index=") { if (!parse_subaddress_indices(local_args[0], subaddr_indices)) return true; From 583eaf3ccb3d1107a518c1dfd93e0ce99bee51e2 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Tue, 24 Jul 2018 14:33:33 +0100 Subject: [PATCH 08/27] wallet2: fix O(n^2) behaviour in import_key_images That takes a lot of time for even not so large wallets --- src/wallet/wallet2.cpp | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 35bbde9d5..5c4170900 100755 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -9580,6 +9580,17 @@ uint64_t wallet2::import_key_images(const std::vector spent_txids; // For each spent key image, search for a tx in m_transfers that uses it as input. std::vector swept_transfers; // If such a spending tx wasn't found in m_transfers, this means the spending tx // was created by sweep_all, so we can't know the spent height and other detailed info. + std::unordered_map spent_key_images; + + for (const transfer_details &td: m_transfers) + { + for (const cryptonote::txin_v& in : td.m_tx.vin) + { + if (in.type() == typeid(cryptonote::txin_to_key)) + spent_key_images.insert(std::make_pair(boost::get(in).k_image, td.m_txid)); + } + } + for(size_t i = 0; i < signed_key_images.size(); ++i) { transfer_details &td = m_transfers[i]; @@ -9593,28 +9604,11 @@ uint64_t wallet2::import_key_images(const std::vectorm_tx.vin) - { - if(in.type() == typeid(cryptonote::txin_to_key) && td.m_key_image == boost::get(in).k_image) - { - is_spent_tx = true; - break; - } - } - if (is_spent_tx) - { - is_spent_tx_found = true; - spent_txids.insert(it->m_txid); - break; - } - } - - if (!is_spent_tx_found) + const std::unordered_map::const_iterator skii = spent_key_images.find(td.m_key_image); + if (skii == spent_key_images.end()) swept_transfers.push_back(i); + else + spent_txids.insert(skii->second); } } MDEBUG("Total: " << print_money(spent) << " spent, " << print_money(unspent) << " unspent"); From 0da1f14aafbc1e6a09af4147104a6f000919eab8 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Mon, 30 Jul 2018 13:15:41 +0100 Subject: [PATCH 09/27] wallet2: guard against bad outputs in import_outputs also some minor speedup --- src/wallet/wallet2.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 5c4170900..67a4f7aad 100755 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -9830,18 +9830,20 @@ size_t wallet2::import_outputs(const std::vector additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx); + THROW_WALLET_EXCEPTION_IF(td.m_tx.vout[td.m_internal_output_index].target.type() != typeid(cryptonote::txout_to_key), + error::wallet_internal_error, "Unsupported output type"); const crypto::public_key& out_key = boost::get(td.m_tx.vout[td.m_internal_output_index].target).key; bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, td.m_key_image, m_account.get_device()); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image"); expand_subaddresses(td.m_subaddr_index); td.m_key_image_known = true; td.m_key_image_partial = false; - THROW_WALLET_EXCEPTION_IF(in_ephemeral.pub != boost::get(td.m_tx.vout[td.m_internal_output_index].target).key, + THROW_WALLET_EXCEPTION_IF(in_ephemeral.pub != out_key, error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key at index " + boost::lexical_cast(i)); m_key_images[td.m_key_image] = m_transfers.size(); m_pub_keys[td.get_public_key()] = m_transfers.size(); - m_transfers.push_back(td); + m_transfers.push_back(std::move(td)); } return m_transfers.size(); From d904ea08a1bd2a738394675063c61956d0793640 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Mon, 30 Jul 2018 13:33:02 +0100 Subject: [PATCH 10/27] wallet2: avoid using arbitrary random values when unknown --- src/wallet/wallet2.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 67a4f7aad..aa6c6eb1f 100755 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -9731,11 +9731,10 @@ uint64_t wallet2::import_key_images(const std::vector(); // spent txid is unknown, so hypothetically set to random + pd.m_block_height = 0; // spent block height is unknown + const crypto::hash &spent_txid = crypto::null_hash; // spent txid is unknown m_confirmed_txs.insert(std::make_pair(spent_txid, pd)); } } From 7cf07e9319ec6f81ecee7ff0a1847c2f9873bb01 Mon Sep 17 00:00:00 2001 From: stoffu Date: Mon, 30 Jul 2018 20:39:05 +0900 Subject: [PATCH 11/27] simplewallet: make sure wallet config is stored right after creation --- src/simplewallet/simplewallet.cpp | 60 ++++++++++++++++++------------- src/simplewallet/simplewallet.h | 8 ++--- 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index b7800d9b5..22901d030 100755 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -2631,6 +2631,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) m_recovery_key = cryptonote::decrypt_key(m_recovery_key, seed_pass); } } + epee::wipeable_string password; if (!m_generate_from_view_key.empty()) { m_wallet_file = m_generate_from_view_key; @@ -2683,8 +2684,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) return false; } - bool r = new_wallet(vm, info.address, boost::none, viewkey); + auto r = new_wallet(vm, info.address, boost::none, viewkey); CHECK_AND_ASSERT_MES(r, false, tr("account creation failed")); + password = *r; } else if (!m_generate_from_spend_key.empty()) { @@ -2702,8 +2704,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) fail_msg_writer() << tr("failed to parse spend key secret key"); return false; } - bool r = new_wallet(vm, m_recovery_key, true, false, ""); + auto r = new_wallet(vm, m_recovery_key, true, false, ""); CHECK_AND_ASSERT_MES(r, false, tr("account creation failed")); + password = *r; } else if (!m_generate_from_keys.empty()) { @@ -2780,8 +2783,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) fail_msg_writer() << tr("view key does not match standard address"); return false; } - bool r = new_wallet(vm, info.address, spendkey, viewkey); + auto r = new_wallet(vm, info.address, spendkey, viewkey); CHECK_AND_ASSERT_MES(r, false, tr("account creation failed")); + password = *r; } // Asks user for all the data required to merge secret keys from multisig wallets into one master wallet, which then gets full control of the multisig wallet. The resulting wallet will be the same as any other regular wallet. @@ -2914,8 +2918,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) } // create wallet - bool r = new_wallet(vm, info.address, spendkey, viewkey); + auto r = new_wallet(vm, info.address, spendkey, viewkey); CHECK_AND_ASSERT_MES(r, false, tr("account creation failed")); + password = *r; } else if (!m_generate_from_json.empty()) @@ -2937,8 +2942,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) { m_wallet_file = m_generate_from_device; // create wallet - bool r = new_wallet(vm, "Ledger"); + auto r = new_wallet(vm, "Ledger"); CHECK_AND_ASSERT_MES(r, false, tr("account creation failed")); + password = *r; // if no block_height is specified, assume its a new account and start it "now" if(m_wallet->get_refresh_from_block_height() == 0) { { @@ -2963,12 +2969,13 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) return false; } m_wallet_file = m_generate_new; - bool r; + boost::optional r; if (m_restore_multisig_wallet) r = new_wallet(vm, multisig_keys, old_language); else r = new_wallet(vm, m_recovery_key, m_restore_deterministic_wallet, m_non_deterministic, old_language); CHECK_AND_ASSERT_MES(r, false, tr("account creation failed")); + password = *r; } if (m_restoring && m_generate_from_json.empty() && m_generate_from_device.empty()) @@ -3050,6 +3057,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) } m_wallet->set_refresh_from_block_height(m_restore_height); } + m_wallet->rewrite(m_wallet_file, password); } else { @@ -3217,15 +3225,16 @@ boost::optional simple_wallet::get_and_verify_passwor return pwd_container; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, +boost::optional simple_wallet::new_wallet(const boost::program_options::variables_map& vm, const crypto::secret_key& recovery_key, bool recover, bool two_random, const std::string &old_language) { auto rc = tools::wallet2::make_new(vm, password_prompter); m_wallet = std::move(rc.first); if (!m_wallet) { - return false; + return {}; } + epee::wipeable_string password = rc.second.password(); if (!m_subaddress_lookahead.empty()) { @@ -3261,7 +3270,7 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, } mnemonic_language = get_mnemonic_language(); if (mnemonic_language.empty()) - return false; + return {}; } m_wallet->set_seed_language(mnemonic_language); @@ -3279,7 +3288,7 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, catch (const std::exception& e) { fail_msg_writer() << tr("failed to generate new wallet: ") << e.what(); - return false; + return {}; } // convert rng value to electrum-style word list @@ -3305,10 +3314,10 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, } success_msg_writer() << "**********************************************************************"; - return true; + return std::move(password); } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, +boost::optional simple_wallet::new_wallet(const boost::program_options::variables_map& vm, const cryptonote::account_public_address& address, const boost::optional& spendkey, const crypto::secret_key& viewkey) { @@ -3316,8 +3325,9 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, m_wallet = std::move(rc.first); if (!m_wallet) { - return false; + return {}; } + epee::wipeable_string password = rc.second.password(); if (!m_subaddress_lookahead.empty()) { @@ -3347,22 +3357,23 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, catch (const std::exception& e) { fail_msg_writer() << tr("failed to generate new wallet: ") << e.what(); - return false; + return {}; } - return true; + return std::move(password); } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, +boost::optional simple_wallet::new_wallet(const boost::program_options::variables_map& vm, const std::string &device_name) { auto rc = tools::wallet2::make_new(vm, password_prompter); m_wallet = std::move(rc.first); if (!m_wallet) { - return false; + return {}; } + epee::wipeable_string password = rc.second.password(); if (!m_subaddress_lookahead.empty()) { @@ -3383,21 +3394,22 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, catch (const std::exception& e) { fail_msg_writer() << tr("failed to generate new wallet: ") << e.what(); - return false; + return {}; } - return true; + return std::move(password); } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, +boost::optional simple_wallet::new_wallet(const boost::program_options::variables_map& vm, const std::string &multisig_keys, const std::string &old_language) { auto rc = tools::wallet2::make_new(vm, password_prompter); m_wallet = std::move(rc.first); if (!m_wallet) { - return false; + return {}; } + epee::wipeable_string password = rc.second.password(); if (!m_subaddress_lookahead.empty()) { @@ -3427,7 +3439,7 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, if (!m_wallet->multisig(&ready, &threshold, &total) || !ready) { fail_msg_writer() << tr("failed to generate new mutlisig wallet"); - return false; + return {}; } message_writer(console_color_white, true) << boost::format(tr("Generated new %u/%u multisig wallet: ")) % threshold % total << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); @@ -3435,10 +3447,10 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, catch (const std::exception& e) { fail_msg_writer() << tr("failed to generate new wallet: ") << e.what(); - return false; + return {}; } - return true; + return std::move(password); } //---------------------------------------------------------------------------------------------------- bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm) diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 125e849d5..e1d60bbd4 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -91,13 +91,13 @@ namespace cryptonote //! \return Prompts user for password and verifies against local file. Logs on error and returns `none` boost::optional get_and_verify_password() const; - bool new_wallet(const boost::program_options::variables_map& vm, const crypto::secret_key& recovery_key, + boost::optional new_wallet(const boost::program_options::variables_map& vm, const crypto::secret_key& recovery_key, bool recover, bool two_random, const std::string &old_language); - bool new_wallet(const boost::program_options::variables_map& vm, const cryptonote::account_public_address& address, + boost::optional new_wallet(const boost::program_options::variables_map& vm, const cryptonote::account_public_address& address, const boost::optional& spendkey, const crypto::secret_key& viewkey); - bool new_wallet(const boost::program_options::variables_map& vm, + boost::optional new_wallet(const boost::program_options::variables_map& vm, const std::string &multisig_keys, const std::string &old_language); - bool new_wallet(const boost::program_options::variables_map& vm, const std::string& device_name); + boost::optional new_wallet(const boost::program_options::variables_map& vm, const std::string& device_name); bool open_wallet(const boost::program_options::variables_map& vm); bool close_wallet(); From ae255e3857bb5142b19a4220d1c906428b40d56c Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Fri, 24 Aug 2018 09:50:34 +0000 Subject: [PATCH 12/27] cryptonote_format_utils: do not early out on invalid tx pubkeys Another such pubkey might be valid --- src/cryptonote_basic/cryptonote_format_utils.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index ca7254bf5..fce729634 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -201,15 +201,25 @@ namespace cryptonote { crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation); bool r = hwdev.generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation); - CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to generate_key_derivation(" << tx_public_key << ", " << ack.m_view_secret_key << ")"); + if (!r) + { + MWARNING("key image helper: failed to generate_key_derivation(" << tx_public_key << ", " << ack.m_view_secret_key << ")"); + memcpy(&recv_derivation, rct::identity().bytes, sizeof(recv_derivation)); + } std::vector additional_recv_derivations; for (size_t i = 0; i < additional_tx_public_keys.size(); ++i) { crypto::key_derivation additional_recv_derivation = AUTO_VAL_INIT(additional_recv_derivation); r = hwdev.generate_key_derivation(additional_tx_public_keys[i], ack.m_view_secret_key, additional_recv_derivation); - CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to generate_key_derivation(" << additional_tx_public_keys[i] << ", " << ack.m_view_secret_key << ")"); - additional_recv_derivations.push_back(additional_recv_derivation); + if (!r) + { + MWARNING("key image helper: failed to generate_key_derivation(" << additional_tx_public_keys[i] << ", " << ack.m_view_secret_key << ")"); + } + else + { + additional_recv_derivations.push_back(additional_recv_derivation); + } } boost::optional subaddr_recv_info = is_out_to_acc_precomp(subaddresses, out_key, recv_derivation, additional_recv_derivations, real_output_index,hwdev); From 332ac6a03af3bae34bcba55aa40ca6582fec527b Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 9 Sep 2018 15:26:50 +0000 Subject: [PATCH 13/27] rpc: return "already mining" in start_mining if already mining --- src/rpc/core_rpc_server.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 3ec67e7e0..8617c7e28 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -863,7 +863,13 @@ namespace cryptonote boost::thread::attributes attrs; attrs.set_stack_size(THREAD_STACK_SIZE); - if(!m_core.get_miner().start(info.address, static_cast(req.threads_count), attrs, req.do_background_mining, req.ignore_battery)) + cryptonote::miner &miner= m_core.get_miner(); + if (miner.is_mining()) + { + res.status = "Already mining"; + return true; + } + if(!miner.start(info.address, static_cast(req.threads_count), attrs, req.do_background_mining, req.ignore_battery)) { res.status = "Failed, mining not started"; LOG_PRINT_L0(res.status); From dc1e56d815321bea210c630f00c6eedbd15f8d40 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Mon, 1 Oct 2018 21:25:56 +0000 Subject: [PATCH 14/27] daemon: do not display uptime when not known --- src/daemon/rpc_command_executor.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index c73d98a84..f7b77233f 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -438,7 +438,8 @@ bool t_rpc_command_executor::show_status() { } } - tools::success_msg_writer() << boost::format("Height: %llu/%llu (%.1f%%) on %s%s, %s, net hash %s, v%u%s, %s, %u(out)+%u(in) connections, uptime %ud %uh %um %us") + std::stringstream str; + str << boost::format("Height: %llu/%llu (%.1f%%) on %s%s, %s, net hash %s, v%u%s, %s, %u(out)+%u(in) connections") % (unsigned long long)ires.height % (unsigned long long)net_height % get_sync_percentage(ires) @@ -451,12 +452,21 @@ bool t_rpc_command_executor::show_status() { % (hfres.state == cryptonote::HardFork::Ready ? "up to date" : hfres.state == cryptonote::HardFork::UpdateNeeded ? "update needed" : "out of date, likely forked") % (unsigned)ires.outgoing_connections_count % (unsigned)ires.incoming_connections_count - % (unsigned int)floor(uptime / 60.0 / 60.0 / 24.0) - % (unsigned int)floor(fmod((uptime / 60.0 / 60.0), 24.0)) - % (unsigned int)floor(fmod((uptime / 60.0), 60.0)) - % (unsigned int)fmod(uptime, 60.0) ; + // restricted RPC does not disclose start time + if (ires.start_time) + { + str << boost::format(", uptime %ud %uh %um %us") + % (unsigned int)floor(uptime / 60.0 / 60.0 / 24.0) + % (unsigned int)floor(fmod((uptime / 60.0 / 60.0), 24.0)) + % (unsigned int)floor(fmod((uptime / 60.0), 60.0)) + % (unsigned int)fmod(uptime, 60.0) + ; + } + + tools::success_msg_writer() << str.str(); + return true; } From 1bbfeb325c5d160450f988feeacc2951e18fe17b Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Tue, 25 Sep 2018 09:57:24 +0000 Subject: [PATCH 15/27] tx_pool: fix tx removal at startup keeping references --- src/cryptonote_core/tx_pool.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 036cb7d33..9694a2a8c 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -1284,6 +1284,7 @@ namespace cryptonote { MWARNING("Failed to parse tx from txpool, removing"); remove.push_back(txid); + return true; } if (!insert_key_images(tx, meta.kept_by_block)) { From d4f07b40de62cb1bbdbb5ddfc342a75953d51852 Mon Sep 17 00:00:00 2001 From: stoffu Date: Tue, 4 Sep 2018 13:00:38 +0900 Subject: [PATCH 16/27] wallet2.get_reserve_proof: throw when specified amount is zero --- src/wallet/wallet2.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index aa6c6eb1f..6b17803f8 100755 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -8915,6 +8915,7 @@ std::string wallet2::get_reserve_proof(const boost::optionalsecond == 0, error::wallet_internal_error, "Proved amount must be greater than 0"); // minimize the number of outputs included in the proof, by only picking the N largest outputs that can cover the requested min reserve amount std::sort(selected_transfers.begin(), selected_transfers.end(), [&](const size_t a, const size_t b) { return m_transfers[a].amount() > m_transfers[b].amount(); }); From 7e6b4601c30e02c24c41b4e26b3df4ae732c9c2d Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Fri, 17 Aug 2018 17:24:24 +0000 Subject: [PATCH 17/27] tx_pool: fix infinite loop when failing to find a meta record --- src/cryptonote_core/tx_pool.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 9694a2a8c..044a66953 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -1095,7 +1095,7 @@ namespace cryptonote LockedTXN lock(m_blockchain); auto sorted_it = m_txs_by_fee_and_receive_time.begin(); - while (sorted_it != m_txs_by_fee_and_receive_time.end()) + for (; sorted_it != m_txs_by_fee_and_receive_time.end(); ++sorted_it) { txpool_tx_meta_t meta; if (!m_blockchain.get_txpool_tx_meta(sorted_it->second, meta)) @@ -1109,7 +1109,6 @@ namespace cryptonote if (max_total_size < total_size + meta.blob_size) { LOG_PRINT_L2(" would exceed maximum block size"); - sorted_it++; continue; } @@ -1122,14 +1121,12 @@ namespace cryptonote if(!get_block_reward(median_size, total_size + meta.blob_size, already_generated_coins, block_reward, version)) { LOG_PRINT_L2(" would exceed maximum block size"); - sorted_it++; continue; } coinbase = block_reward + fee + meta.fee; if (coinbase < template_accept_threshold(best_coinbase)) { LOG_PRINT_L2(" would decrease coinbase to " << print_money(coinbase)); - sorted_it++; continue; } } @@ -1173,13 +1170,11 @@ namespace cryptonote if (!ready) { LOG_PRINT_L2(" not ready to go"); - sorted_it++; continue; } if (have_key_images(k_images, tx)) { LOG_PRINT_L2(" key images already seen"); - sorted_it++; continue; } @@ -1188,7 +1183,6 @@ namespace cryptonote fee += meta.fee; best_coinbase = coinbase; append_key_images(k_images, tx); - sorted_it++; LOG_PRINT_L2(" added, new block size " << total_size << "/" << max_total_size << ", coinbase " << print_money(best_coinbase)); } From c4bdd5699cf5dc086a56e379d086c29e1964d737 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Thu, 16 Aug 2018 18:15:47 +0000 Subject: [PATCH 18/27] epee: some speedup in parsing --- contrib/epee/include/storages/parserse_base_utils.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/contrib/epee/include/storages/parserse_base_utils.h b/contrib/epee/include/storages/parserse_base_utils.h index c809392f4..8c6c1a64d 100644 --- a/contrib/epee/include/storages/parserse_base_utils.h +++ b/contrib/epee/include/storages/parserse_base_utils.h @@ -28,6 +28,8 @@ #pragma once +#include + namespace epee { namespace misc_utils @@ -36,8 +38,12 @@ namespace misc_utils { inline std::string transform_to_escape_sequence(const std::string& src) { - //std::stringstream res; + static const char escaped[] = "\b\f\n\r\t\v\"\\/"; + if (std::find_first_of(src.begin(), src.end(), escaped, escaped + sizeof(escaped)) == src.end()) + return src; + std::string res; + res.reserve(2 * src.size()); for(std::string::const_iterator it = src.begin(); it!=src.end(); ++it) { switch(*it) @@ -84,6 +90,7 @@ namespace misc_utils inline void match_string2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val) { val.clear(); + val.reserve(std::distance(star_end_string, buf_end)); bool escape_mode = false; std::string::const_iterator it = star_end_string; ++it; From 47f7cf68aeaf51838cc794297e4693fc94a80275 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Thu, 16 Aug 2018 18:15:07 +0000 Subject: [PATCH 19/27] epee: resize vectors where possible in serialization to avoid unnecessary repeated reallocation --- .../serialization/keyvalue_serialization_overloads.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h index 7087136cc..db4b1af5e 100644 --- a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h +++ b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h @@ -35,6 +35,11 @@ namespace epee { + namespace + { + template void hint_resize(C &container, size_t size) {} + template void hint_resize(std::vector &container, size_t size) { container.reserve(size); } + } namespace serialization { @@ -158,6 +163,7 @@ namespace epee false, "size in blob " << loaded_size << " not have not zero modulo for sizeof(value_type) = " << sizeof(typename stl_container::value_type)); size_t count = (loaded_size/sizeof(typename stl_container::value_type)); + hint_resize(container, count); for(size_t i = 0; i < count; i++) container.insert(container.end(), *(pelem++)); } From 00c6056e9879183f3ad41161f0228c98534dac76 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Wed, 15 Aug 2018 12:15:39 +0000 Subject: [PATCH 20/27] simplewallet: allow named priority levels for default-priority to match those used by the various transfer functions --- src/simplewallet/simplewallet.cpp | 46 +++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 22901d030..455e1fda6 100755 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -525,6 +525,18 @@ bool parse_priority(const std::string& arg, uint32_t& priority) return false; } +std::string join_priority_strings(const char *delimiter) +{ + std::string s; + for (size_t n = 0; n < allowed_priority_strings.size(); ++n) + { + if (!s.empty()) + s += delimiter; + s += allowed_priority_strings[n]; + } + return s; +} + std::string simple_wallet::get_commands_str() { std::stringstream ss; @@ -1611,12 +1623,12 @@ bool simple_wallet::set_store_tx_info(const std::vector &args/* = s bool simple_wallet::set_default_priority(const std::vector &args/* = std::vector()*/) { - int priority = 0; + uint32_t priority = 0; try { if (strchr(args[1].c_str(), '-')) { - fail_msg_writer() << tr("priority must be 0, 1, 2, 3, or 4 "); + fail_msg_writer() << tr("priority must be either 0, 1, 2, 3, or 4, or one of: ") << join_priority_strings(", "); return true; } if (args[1] == "0") @@ -1625,11 +1637,23 @@ bool simple_wallet::set_default_priority(const std::vector &args/* } else { - priority = boost::lexical_cast(args[1]); - if (priority < 1 || priority > 4) + bool found = false; + for (size_t n = 0; n < allowed_priority_strings.size(); ++n) { - fail_msg_writer() << tr("priority must be 0, 1, 2, 3, or 4"); - return true; + if (allowed_priority_strings[n] == args[1]) + { + found = true; + priority = n; + } + } + if (!found) + { + priority = boost::lexical_cast(args[1]); + if (priority < 1 || priority > 4) + { + fail_msg_writer() << tr("priority must be either 0, 1, 2, 3, or 4, or one of: ") << join_priority_strings(", "); + return true; + } } } @@ -1643,7 +1667,7 @@ bool simple_wallet::set_default_priority(const std::vector &args/* } catch(const boost::bad_lexical_cast &) { - fail_msg_writer() << tr("priority must be 0, 1, 2, 3, or 4"); + fail_msg_writer() << tr("priority must be either 0, 1, 2, 3, or 4, or one of: ") << join_priority_strings(", "); return true; } catch(...) @@ -2312,13 +2336,17 @@ bool simple_wallet::set_variable(const std::vector &args) std::string seed_language = m_wallet->get_seed_language(); if (m_use_english_language_names) seed_language = crypto::ElectrumWords::get_english_name_for(seed_language); + std::string priority_string = "invalid"; + uint32_t priority = m_wallet->get_default_priority(); + if (priority < allowed_priority_strings.size()) + priority_string = allowed_priority_strings[priority]; success_msg_writer() << "seed = " << seed_language; success_msg_writer() << "always-confirm-transfers = " << m_wallet->always_confirm_transfers(); success_msg_writer() << "print-ring-members = " << m_wallet->print_ring_members(); success_msg_writer() << "store-tx-info = " << m_wallet->store_tx_info(); success_msg_writer() << "auto-refresh = " << m_wallet->auto_refresh(); success_msg_writer() << "refresh-type = " << get_refresh_type_name(m_wallet->get_refresh_type()); - success_msg_writer() << "priority = " << m_wallet->get_default_priority(); + success_msg_writer() << "priority = " << priority<< " (" << priority_string << ")"; success_msg_writer() << "confirm-missing-payment-id = " << m_wallet->confirm_missing_payment_id(); success_msg_writer() << "ask-password = " << m_wallet->ask_password(); success_msg_writer() << "unit = " << cryptonote::get_unit(cryptonote::get_default_decimal_point()); @@ -2372,7 +2400,7 @@ bool simple_wallet::set_variable(const std::vector &args) CHECK_SIMPLE_VARIABLE("store-tx-info", set_store_tx_info, tr("0 or 1")); CHECK_SIMPLE_VARIABLE("auto-refresh", set_auto_refresh, tr("0 or 1")); CHECK_SIMPLE_VARIABLE("refresh-type", set_refresh_type, tr("full (slowest, no assumptions); optimize-coinbase (fast, assumes the whole coinbase is paid to a single address); no-coinbase (fastest, assumes we receive no coinbase transaction), default (same as optimize-coinbase)")); - CHECK_SIMPLE_VARIABLE("priority", set_default_priority, tr("0, 1, 2, 3, or 4")); + CHECK_SIMPLE_VARIABLE("priority", set_default_priority, tr("0, 1, 2, 3, or 4, or one of ") << join_priority_strings(", ")); CHECK_SIMPLE_VARIABLE("confirm-missing-payment-id", set_confirm_missing_payment_id, tr("0 or 1")); CHECK_SIMPLE_VARIABLE("ask-password", set_ask_password, tr("0 or 1")); CHECK_SIMPLE_VARIABLE("unit", set_unit, tr("wownero, millinero, micronero, nanonero, piconero")); From bbd251c48fd74c01ec130d5b35737a12c2840575 Mon Sep 17 00:00:00 2001 From: rbrunner7 Date: Sun, 12 Aug 2018 14:49:32 +0200 Subject: [PATCH 21/27] simplewallet: Simplify LOCK_IDLE_SCOPE macro --- src/simplewallet/simplewallet.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 455e1fda6..36f1278df 100755 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -93,13 +93,8 @@ typedef cryptonote::simple_wallet sw; m_auto_refresh_enabled.store(false, std::memory_order_relaxed); \ /* stop any background refresh, and take over */ \ m_wallet->stop(); \ - m_idle_mutex.lock(); \ - while (m_auto_refresh_refreshing) \ - m_idle_cond.notify_one(); \ - m_idle_mutex.unlock(); \ -/* if (auto_refresh_run)*/ \ - /*m_auto_refresh_thread.join();*/ \ boost::unique_lock lock(m_idle_mutex); \ + m_idle_cond.notify_all(); \ epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ \ m_auto_refresh_enabled.store(auto_refresh_enabled, std::memory_order_relaxed); \ }) From 9021fe99b188a6eb7ad6c0d7cc8bb1843c08e68d Mon Sep 17 00:00:00 2001 From: fireice-uk Date: Fri, 10 Aug 2018 16:49:18 +0200 Subject: [PATCH 22/27] node_rpc_proxy: fix fork earliest height caching [RYO backport] xref https://github.com/ryo-currency/ryo-currency/pull/86 --- src/wallet/node_rpc_proxy.cpp | 2 +- src/wallet/wallet2.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wallet/node_rpc_proxy.cpp b/src/wallet/node_rpc_proxy.cpp index c5d869354..3ac7d4406 100644 --- a/src/wallet/node_rpc_proxy.cpp +++ b/src/wallet/node_rpc_proxy.cpp @@ -146,7 +146,7 @@ boost::optional NodeRPCProxy::get_earliest_height(uint8_t version, CHECK_AND_ASSERT_MES(r, std::string(), "Failed to connect to daemon"); CHECK_AND_ASSERT_MES(resp_t.status != CORE_RPC_STATUS_BUSY, resp_t.status, "Failed to connect to daemon"); CHECK_AND_ASSERT_MES(resp_t.status == CORE_RPC_STATUS_OK, resp_t.status, "Failed to get hard fork status"); - m_earliest_height[version] = resp_t.enabled ? resp_t.earliest_height : std::numeric_limits::max(); + m_earliest_height[version] = resp_t.earliest_height; } earliest_height = m_earliest_height[version]; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 6b17803f8..38f78582a 100755 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -8132,7 +8132,7 @@ bool wallet2::use_fork_rules(uint8_t version, int64_t early_blocks) const result = m_node_rpc_proxy.get_earliest_height(version, earliest_height); throw_on_rpc_response_error(result, "get_hard_fork_info"); - bool close_enough = height >= earliest_height - early_blocks && earliest_height != std::numeric_limits::max(); // start using the rules that many blocks beforehand + bool close_enough = height >= earliest_height - early_blocks; // start using the rules that many blocks beforehand if (close_enough) LOG_PRINT_L2("Using v" << (unsigned)version << " rules"); else From 835caf37222355b8e5c215b083291d5b02f12254 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Tue, 7 Aug 2018 12:48:04 +0000 Subject: [PATCH 23/27] simplewallet: add a warning and prompt on rescan_blockchain Many people are using this as a "let's see what this does" command when something doesn't work as they thought it should, and thus destroying info that they might still need. --- src/simplewallet/simplewallet.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 36f1278df..3bf86a4e4 100755 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -2201,7 +2201,7 @@ simple_wallet::simple_wallet() tr("Show the unspent outputs of a specified address within an optional amount range.")); m_cmd_binder.set_handler("rescan_bc", boost::bind(&simple_wallet::rescan_blockchain, this, _1), - tr("Rescan the blockchain from scratch.")); + tr("Rescan the blockchain from scratch, losing any information which can not be recovered from the blockchain itself.")); m_cmd_binder.set_handler("set_tx_note", boost::bind(&simple_wallet::set_tx_note, this, _1), tr("set_tx_note [free text note]"), @@ -6332,6 +6332,14 @@ bool simple_wallet::unspent_outputs(const std::vector &args_) //---------------------------------------------------------------------------------------------------- bool simple_wallet::rescan_blockchain(const std::vector &args_) { + message_writer() << tr("Warning: this will lose any information which can not be recovered from the blockchain."); + message_writer() << tr("This includes destination addresses, tx secret keys, tx notes, etc"); + std::string confirm = input_line(tr("Rescan anyway ? (Y/Yes/N/No): ")); + if(!std::cin.eof()) + { + if (!command_line::is_yes(confirm)) + return true; + } return refresh_main(0, true); } //---------------------------------------------------------------------------------------------------- From bb0ac27a4a624f59deb7b083f4291c263df5d219 Mon Sep 17 00:00:00 2001 From: rbrunner7 Date: Sun, 5 Aug 2018 09:58:33 +0200 Subject: [PATCH 24/27] simplewallet: correct number of human-readable months --- src/simplewallet/simplewallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 3bf86a4e4..2679c2bfe 100755 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -6006,7 +6006,7 @@ static std::string get_human_readable_timespan(std::chrono::seconds seconds) if (ts < 3600 * 24 * 30.5) return std::to_string((uint64_t)(ts / (3600 * 24))) + tr(" days"); if (ts < 3600 * 24 * 365.25) - return std::to_string((uint64_t)(ts / (3600 * 24 * 365.25))) + tr(" months"); + return std::to_string((uint64_t)(ts / (3600 * 24 * 30.5))) + tr(" months"); return tr("a long time"); } //---------------------------------------------------------------------------------------------------- From b491ff61c5801d78737b1ae069175c3749309481 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Wed, 25 Jul 2018 23:00:19 +0100 Subject: [PATCH 25/27] epee: set jsonrpc to "2.0" in parse error return data --- contrib/epee/include/net/http_server_handlers_map2.h | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/epee/include/net/http_server_handlers_map2.h b/contrib/epee/include/net/http_server_handlers_map2.h index 429e3e1af..00a867d3e 100644 --- a/contrib/epee/include/net/http_server_handlers_map2.h +++ b/contrib/epee/include/net/http_server_handlers_map2.h @@ -122,6 +122,7 @@ if(!ps.load_from_json(query_info.m_body)) \ { \ boost::value_initialized rsp; \ + static_cast(rsp).jsonrpc = "2.0"; \ static_cast(rsp).error.code = -32700; \ static_cast(rsp).error.message = "Parse error"; \ epee::serialization::store_t_to_json(static_cast(rsp), response_info.m_body); \ From 308a8f69adf8bcbb2e550261fd53105d418c7534 Mon Sep 17 00:00:00 2001 From: stoffu Date: Tue, 24 Jul 2018 16:17:49 +0900 Subject: [PATCH 26/27] daemon.print_bc: don't print difficulty twice --- src/daemon/rpc_command_executor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index f7b77233f..8af512208 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -564,7 +564,7 @@ bool t_rpc_command_executor::print_blockchain_info(uint64_t start_block_index, u if (!first) std::cout << std::endl; std::cout - << "height: " << header.height << ", timestamp: " << header.timestamp << ", difficulty: " << header.difficulty + << "height: " << header.height << ", timestamp: " << header.timestamp << ", size: " << header.block_size << ", transactions: " << header.num_txes << std::endl << "major version: " << (unsigned)header.major_version << ", minor version: " << (unsigned)header.minor_version << std::endl << "block id: " << header.hash << ", previous block id: " << header.prev_hash << std::endl From b40a81c6946a2961542922310d3828d04531063e Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Fri, 23 Mar 2018 15:43:38 +0000 Subject: [PATCH 27/27] wallet2: use a gamma distribution to pick fake outs as per "An Empirical Analysis of Linkability in the Monero Blockchain", by Miller et al. --- src/wallet/wallet2.cpp | 143 ++++++++++++++++++++++++++++++++--------- src/wallet/wallet2.h | 2 +- 2 files changed, 115 insertions(+), 30 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 38f78582a..f9ea304d2 100755 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2398,7 +2398,7 @@ bool wallet2::refresh(uint64_t & blocks_fetched, bool& received_money, bool& ok) return ok; } //---------------------------------------------------------------------------------------------------- -bool wallet2::get_output_distribution(uint64_t &start_height, std::vector &distribution) +bool wallet2::get_rct_distribution(uint64_t &start_height, std::vector &distribution) { uint32_t rpc_version; boost::optional result = m_node_rpc_proxy.get_rpc_version(rpc_version); @@ -5922,22 +5922,42 @@ void wallet2::get_outs(std::vector> 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; + // if we have at least one rct out, get the distribution, or fall back to the previous system + uint64_t rct_start_height; + std::vector rct_offsets; + bool has_rct = false; + for (size_t idx: selected_transfers) + if (m_transfers[idx].is_rct()) + { has_rct = true; break; } + const bool has_rct_distribution = has_rct && get_rct_distribution(rct_start_height, rct_offsets); + if (has_rct_distribution) + { + // check we're clear enough of rct start, to avoid corner cases below + THROW_WALLET_EXCEPTION_IF(rct_offsets.size() <= CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE, + error::get_output_distribution, "Not enough rct outputs"); + } + // get histogram for the amounts we need cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request req_t = AUTO_VAL_INIT(req_t); cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response resp_t = AUTO_VAL_INIT(resp_t); - m_daemon_rpc_mutex.lock(); + // request histogram for all outputs, except 0 if we have the rct distribution for(size_t idx: selected_transfers) - req_t.amounts.push_back(m_transfers[idx].is_rct() ? 0 : m_transfers[idx].amount()); - 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.unlocked = true; - req_t.recent_cutoff = time(NULL) - RECENT_OUTPUT_ZONE; - bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, m_http_client, rpc_timeout); - 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_histogram"); - THROW_WALLET_EXCEPTION_IF(resp_t.status != CORE_RPC_STATUS_OK, error::get_histogram_error, resp_t.status); + if (!m_transfers[idx].is_rct() || !has_rct_distribution) + req_t.amounts.push_back(m_transfers[idx].is_rct() ? 0 : m_transfers[idx].amount()); + if (!req_t.amounts.empty()) + { + 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.unlocked = true; + req_t.recent_cutoff = time(NULL) - RECENT_OUTPUT_ZONE; + m_daemon_rpc_mutex.lock(); + bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, m_http_client, rpc_timeout); + 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_histogram"); + THROW_WALLET_EXCEPTION_IF(resp_t.status != CORE_RPC_STATUS_OK, error::get_histogram_error, resp_t.status); + } // if we want to segregate fake outs pre or post fork, get distribution std::unordered_map> segregation_limit; @@ -5993,6 +6013,36 @@ void wallet2::get_outs(std::vector> COMMAND_RPC_GET_OUTPUTS_BIN::request req = AUTO_VAL_INIT(req); COMMAND_RPC_GET_OUTPUTS_BIN::response daemon_resp = AUTO_VAL_INIT(daemon_resp); + struct gamma_engine + { + typedef uint64_t result_type; + static constexpr result_type min() { return 0; } + static constexpr result_type max() { return std::numeric_limits::max(); } + result_type operator()() { return crypto::rand(); } + } engine; + static const double shape = 19.28/*16.94*/; + //static const double shape = m_testnet ? 17.02 : 17.28; + static const double scale = 1/1.61; + std::gamma_distribution gamma(shape, scale); + auto pick_gamma = [&]() + { + double x = gamma(engine); + x = exp(x); + uint64_t block_offset = x / DIFFICULTY_TARGET_V2; // this assumes constant target over the whole rct range + if (block_offset >= rct_offsets.size() - 1) + return std::numeric_limits::max(); // bad pick + block_offset = rct_offsets.size() - 2 - block_offset; + THROW_WALLET_EXCEPTION_IF(block_offset >= rct_offsets.size() - 1, error::wallet_internal_error, "Bad offset calculation"); + THROW_WALLET_EXCEPTION_IF(rct_offsets[block_offset + 1] < rct_offsets[block_offset], + error::get_output_distribution, "Decreasing offsets in rct distribution: " + + std::to_string(block_offset) + ": " + std::to_string(rct_offsets[block_offset]) + ", " + + std::to_string(block_offset + 1) + ": " + std::to_string(rct_offsets[block_offset + 1])); + uint64_t n_rct = rct_offsets[block_offset + 1] - rct_offsets[block_offset]; + if (n_rct == 0) + return rct_offsets[block_offset] ? rct_offsets[block_offset] - 1 : 0; + return rct_offsets[block_offset] + crypto::rand() % n_rct; + }; + size_t num_selected_transfers = 0; for(size_t idx: selected_transfers) { @@ -6003,6 +6053,7 @@ void wallet2::get_outs(std::vector> // request more for rct in base recent (locked) coinbases are picked, since they're locked for longer size_t requested_outputs_count = base_requested_outputs_count + (td.is_rct() ? CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW - CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE : 0); size_t start = req.outputs.size(); + bool use_histogram = amount != 0 || !has_rct_distribution; const bool output_is_pre_fork = td.m_block_height < segregation_fork_height; uint64_t num_outs = 0, num_recent_outs = 0; @@ -6058,26 +6109,41 @@ void wallet2::get_outs(std::vector> num_post_fork_outs = num_outs - segregation_limit[amount].first; } - LOG_PRINT_L1("" << num_outs << " unlocked outputs of size " << print_money(amount)); - THROW_WALLET_EXCEPTION_IF(num_outs == 0, error::wallet_internal_error, - "histogram reports no unlocked outputs for " + boost::lexical_cast(amount) + ", not even ours"); - THROW_WALLET_EXCEPTION_IF(num_recent_outs > num_outs, error::wallet_internal_error, - "histogram reports more recent outs than outs for " + boost::lexical_cast(amount)); + if (use_histogram) + { + LOG_PRINT_L1("" << num_outs << " unlocked outputs of size " << print_money(amount)); + THROW_WALLET_EXCEPTION_IF(num_outs == 0, error::wallet_internal_error, + "histogram reports no unlocked outputs for " + boost::lexical_cast(amount) + ", not even ours"); + THROW_WALLET_EXCEPTION_IF(num_recent_outs > num_outs, error::wallet_internal_error, + "histogram reports more recent outs than outs for " + boost::lexical_cast(amount)); + } + else + { + // the base offset of the first rct output in the first unlocked block (or the one to be if there's none) + num_outs = rct_offsets[rct_offsets.size() - CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE]; + LOG_PRINT_L1("" << num_outs << " unlocked rct outputs"); + THROW_WALLET_EXCEPTION_IF(num_outs == 0, error::wallet_internal_error, + "histogram reports no unlocked rct outputs, not even ours"); + } - // how many fake outs to draw on a pre-fork triangular distribution + // how many fake outs to draw on a pre-fork distribution size_t pre_fork_outputs_count = requested_outputs_count * pre_fork_num_out_ratio; size_t post_fork_outputs_count = requested_outputs_count * post_fork_num_out_ratio; // how many fake outs to draw otherwise size_t normal_output_count = requested_outputs_count - pre_fork_outputs_count - post_fork_outputs_count; - // X% of those outs are to be taken from recent outputs - size_t recent_outputs_count = normal_output_count * RECENT_OUTPUT_RATIO; - if (recent_outputs_count == 0) - recent_outputs_count = 1; // ensure we have at least one, if possible - if (recent_outputs_count > num_recent_outs) - recent_outputs_count = num_recent_outs; - if (td.m_global_output_index >= num_outs - num_recent_outs && recent_outputs_count > 0) - --recent_outputs_count; // if the real out is recent, pick one less recent fake out + size_t recent_outputs_count = 0; + if (use_histogram) + { + // X% of those outs are to be taken from recent outputs + recent_outputs_count = normal_output_count * RECENT_OUTPUT_RATIO; + if (recent_outputs_count == 0) + recent_outputs_count = 1; // ensure we have at least one, if possible + if (recent_outputs_count > num_recent_outs) + recent_outputs_count = num_recent_outs; + if (td.m_global_output_index >= num_outs - num_recent_outs && recent_outputs_count > 0) + --recent_outputs_count; // if the real out is recent, pick one less recent fake out + } LOG_PRINT_L1("Fake output makeup: " << requested_outputs_count << " requested: " << recent_outputs_count << " recent, " << pre_fork_outputs_count << " pre-fork, " << post_fork_outputs_count << " post-fork, " << (requested_outputs_count - recent_outputs_count - pre_fork_outputs_count - post_fork_outputs_count) << " full-chain"); @@ -6157,7 +6223,26 @@ void wallet2::get_outs(std::vector> uint64_t i; const char *type = ""; - if (num_found - 1 < recent_outputs_count) // -1 to account for the real one we seeded with + if (amount == 0 && has_rct_distribution) + { + // gamma distribution + if (num_found -1 < recent_outputs_count + pre_fork_outputs_count) + { + do i = pick_gamma(); while (i >= segregation_limit[amount].first); + type = "pre-fork gamma"; + } + else if (num_found -1 < recent_outputs_count + pre_fork_outputs_count + post_fork_outputs_count) + { + do i = pick_gamma(); while (i < segregation_limit[amount].first || i >= num_outs); + type = "post-fork gamma"; + } + else + { + do i = pick_gamma(); while (i >= num_outs); + type = "gamma"; + } + } + else if (num_found - 1 < recent_outputs_count) // -1 to account for the real one we seeded with { // triangular distribution over [a,b) with a=0, mode c=b=up_index_limit uint64_t r = crypto::rand() % ((uint64_t)1 << 53); @@ -6222,7 +6307,7 @@ void wallet2::get_outs(std::vector> // get the keys for those m_daemon_rpc_mutex.lock(); - r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, daemon_resp, m_http_client, rpc_timeout); + bool r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, daemon_resp, m_http_client, rpc_timeout); m_daemon_rpc_mutex.unlock(); THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_outs.bin"); THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_outs.bin"); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index af4c9ad8e..c6ae2e29f 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1139,7 +1139,7 @@ namespace tools bool remove_rings(const cryptonote::transaction_prefix &tx); bool get_ring(const crypto::chacha_key &key, const crypto::key_image &key_image, std::vector &outs); - bool get_output_distribution(uint64_t &start_height, std::vector &distribution); + bool get_rct_distribution(uint64_t &start_height, std::vector &distribution); uint64_t get_segregation_fork_height() const;