diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index b05b68e89..7ce51a1f6 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -2091,6 +2091,19 @@ bool simple_wallet::set_segregation_height(const std::vector &args/ return true; } +bool simple_wallet::set_ignore_fractional_outputs(const std::vector &args/* = std::vector()*/) +{ + const auto pwd_container = get_and_verify_password(); + if (pwd_container) + { + parse_bool_and_use(args[1], [&](bool r) { + m_wallet->ignore_fractional_outputs(r); + m_wallet->rewrite(m_wallet_file, pwd_container->password()); + }); + } + return true; +} + bool simple_wallet::help(const std::vector &args/* = std::vector()*/) { if(args.empty()) @@ -2478,6 +2491,7 @@ bool simple_wallet::set_variable(const std::vector &args) const std::pair lookahead = m_wallet->get_subaddress_lookahead(); success_msg_writer() << "subaddress-lookahead = " << lookahead.first << ":" << lookahead.second; success_msg_writer() << "segregation-height = " << m_wallet->segregation_height(); + success_msg_writer() << "ignore-fractional-outputs = " << m_wallet->ignore_fractional_outputs(); return true; } else @@ -2532,6 +2546,7 @@ bool simple_wallet::set_variable(const std::vector &args) CHECK_SIMPLE_VARIABLE("key-reuse-mitigation2", set_key_reuse_mitigation2, tr("0 or 1")); CHECK_SIMPLE_VARIABLE("subaddress-lookahead", set_subaddress_lookahead, tr(":")); CHECK_SIMPLE_VARIABLE("segregation-height", set_segregation_height, tr("unsigned integer")); + CHECK_SIMPLE_VARIABLE("ignore-fractional-outputs", set_ignore_fractional_outputs, tr("0 or 1")); } fail_msg_writer() << tr("set: unrecognized argument(s)"); return true; diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 7a788d432..1f2765055 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -137,6 +137,7 @@ namespace cryptonote bool set_key_reuse_mitigation2(const std::vector &args = std::vector()); bool set_subaddress_lookahead(const std::vector &args = std::vector()); bool set_segregation_height(const std::vector &args = std::vector()); + bool set_ignore_fractional_outputs(const std::vector &args = std::vector()); bool help(const std::vector &args = std::vector()); bool start_mining(const std::vector &args); bool stop_mining(const std::vector &args); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 35cddcb05..2dea40dd3 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -676,6 +676,7 @@ wallet2::wallet2(network_type nettype, bool restricted): m_segregate_pre_fork_outputs(true), m_key_reuse_mitigation2(true), m_segregation_height(0), + m_ignore_fractional_outputs(true), m_is_initialized(false), m_restricted(restricted), is_old_file_format(false), @@ -2800,6 +2801,9 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable value2.SetUint(m_segregation_height); json.AddMember("segregation_height", value2, json.GetAllocator()); + value2.SetInt(m_ignore_fractional_outputs ? 1 : 0); + json.AddMember("ignore_fractional_outputs", value2, json.GetAllocator()); + value2.SetUint(m_subaddress_lookahead_major); json.AddMember("subaddress_lookahead_major", value2, json.GetAllocator()); @@ -2882,6 +2886,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ m_segregate_pre_fork_outputs = true; m_key_reuse_mitigation2 = true; m_segregation_height = 0; + m_ignore_fractional_outputs = true; m_subaddress_lookahead_major = SUBADDRESS_LOOKAHEAD_MAJOR; m_subaddress_lookahead_minor = SUBADDRESS_LOOKAHEAD_MINOR; m_key_on_device = false; @@ -3008,6 +3013,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ m_key_reuse_mitigation2 = field_key_reuse_mitigation2; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, segregation_height, int, Uint, false, 0); m_segregation_height = field_segregation_height; + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, ignore_fractional_outputs, int, Int, false, true); + m_ignore_fractional_outputs = field_ignore_fractional_outputs; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_major, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MAJOR); m_subaddress_lookahead_major = field_subaddress_lookahead_major; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_minor, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MINOR); @@ -7691,12 +7698,24 @@ std::vector wallet2::create_transactions_2(std::vector tx_size_two_rings, error::wallet_internal_error, "Estimated tx size with 1 input is larger than with 2 inputs!"); + const size_t tx_size_per_ring = tx_size_two_rings - tx_size_one_ring; + const uint64_t fractional_threshold = (fee_multiplier * fee_per_kb * tx_size_per_ring) / 1024; + // gather all dust and non-dust outputs belonging to specified subaddresses size_t num_nondust_outputs = 0; size_t num_dust_outputs = 0; for (size_t i = 0; i < m_transfers.size(); ++i) { const transfer_details& td = m_transfers[i]; + if (m_ignore_fractional_outputs && td.amount() < fractional_threshold) + { + MDEBUG("Ignoring output " << i << " of amount " << print_money(td.amount()) << " which is below threshold " << print_money(fractional_threshold)); + continue; + } if (!td.m_spent && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1) { const uint32_t index_minor = td.m_subaddr_index.minor; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 4d22b6915..1c2ee75dd 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -925,6 +925,8 @@ namespace tools void key_reuse_mitigation2(bool value) { m_key_reuse_mitigation2 = value; } uint64_t segregation_height() const { return m_segregation_height; } void segregation_height(uint64_t height) { m_segregation_height = height; } + bool ignore_fractional_outputs() const { return m_ignore_fractional_outputs; } + void ignore_fractional_outputs(bool value) { m_ignore_fractional_outputs = value; } bool confirm_non_default_ring_size() const { return m_confirm_non_default_ring_size; } void confirm_non_default_ring_size(bool always) { m_confirm_non_default_ring_size = always; } @@ -1284,6 +1286,7 @@ namespace tools bool m_segregate_pre_fork_outputs; bool m_key_reuse_mitigation2; uint64_t m_segregation_height; + bool m_ignore_fractional_outputs; bool m_is_initialized; NodeRPCProxy m_node_rpc_proxy; std::unordered_set m_scanned_pool_txs[2];