From 0a97b3784dad6355cf21042b37bd55744936922e Mon Sep 17 00:00:00 2001 From: wowario Date: Fri, 26 Oct 2018 21:39:50 +0300 Subject: [PATCH] revert wallet2: use a gamma distribution to pick fake outs --- src/wallet/wallet2.cpp | 141 +++++++++-------------------------------- src/wallet/wallet2.h | 2 +- 2 files changed, 30 insertions(+), 113 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 635f1bb41..4c4ee8bf3 100755 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2399,7 +2399,7 @@ bool wallet2::refresh(uint64_t & blocks_fetched, bool& received_money, bool& ok) return ok; } //---------------------------------------------------------------------------------------------------- -bool wallet2::get_rct_distribution(uint64_t &start_height, std::vector &distribution) +bool wallet2::get_output_distribution(uint64_t &start_height, std::vector &distribution) { uint32_t rpc_version; boost::optional result = m_node_rpc_proxy.get_rpc_version(rpc_version); @@ -5923,42 +5923,23 @@ 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); - // request histogram for all outputs, except 0 if we have the rct distribution + m_daemon_rpc_mutex.lock(); for(size_t idx: selected_transfers) - 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); - } + 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 we want to segregate fake outs pre or post fork, get distribution std::unordered_map> segregation_limit; @@ -6014,35 +5995,6 @@ 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) @@ -6054,7 +6006,6 @@ 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; @@ -6110,41 +6061,26 @@ void wallet2::get_outs(std::vector> num_post_fork_outs = num_outs - segregation_limit[amount].first; } - 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"); - } + 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)); - // how many fake outs to draw on a pre-fork distribution + // how many fake outs to draw on a pre-fork triangular 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; - 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 - } + // 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 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"); @@ -6224,26 +6160,7 @@ void wallet2::get_outs(std::vector> uint64_t i; const char *type = ""; - 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 + 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); @@ -6308,7 +6225,7 @@ void wallet2::get_outs(std::vector> // get the keys for those m_daemon_rpc_mutex.lock(); - bool r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, daemon_resp, m_http_client, rpc_timeout); + 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 ed02d7a28..f2e861f18 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_rct_distribution(uint64_t &start_height, std::vector &distribution); + bool get_output_distribution(uint64_t &start_height, std::vector &distribution); uint64_t get_segregation_fork_height() const;