diff options
author | Riccardo Spagni <ric@spagni.net> | 2015-10-11 21:28:06 +0200 |
---|---|---|
committer | Riccardo Spagni <ric@spagni.net> | 2015-10-11 21:28:14 +0200 |
commit | 8169d429bf2a0e9beee966b120627f7c9cb436ed (patch) | |
tree | 719d2d3a59330e1cb56dd698e8c1d8bb4012def3 | |
parent | Merge pull request #423 (diff) | |
parent | simplewallet: bump default mixin from 3 to 4 (diff) | |
download | monero-8169d429bf2a0e9beee966b120627f7c9cb436ed.tar.xz |
Merge pull request #425
79c95c1 simplewallet: bump default mixin from 3 to 4 (moneromooo-monero)
ac90d48 from hard fork 2, all outputs must be decomposed (moneromooo-monero)
90ccad1 from hard fork 2, claim a quantized reward in coinbase (moneromooo-monero)
22b1570 cryptonote_format_utils: add a function to tell if an amount is canonical (moneromooo-monero)
-rw-r--r-- | src/cryptonote_config.h | 1 | ||||
-rw-r--r-- | src/cryptonote_core/blockchain.cpp | 29 | ||||
-rw-r--r-- | src/cryptonote_core/blockchain.h | 1 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_format_utils.cpp | 43 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_format_utils.h | 3 | ||||
-rw-r--r-- | src/cryptonote_core/tx_pool.cpp | 6 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.cpp | 2 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 34 | ||||
-rw-r--r-- | src/wallet/wallet2.h | 55 |
9 files changed, 121 insertions, 53 deletions
diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index c6aa064cf..b042088bd 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -118,6 +118,7 @@ namespace config uint64_t const DEFAULT_FEE_ATOMIC_XMR_PER_KB = 500; // Just a placeholder! Change me! uint8_t const FEE_CALCULATION_MAX_RETRIES = 10; uint64_t const DEFAULT_DUST_THRESHOLD = ((uint64_t)10000000000); // pow(10, 10) + uint64_t const BASE_REWARD_CLAMP_THRESHOLD = ((uint64_t)100000000); // pow(10, 8) std::string const P2P_REMOTE_DEBUG_TRUSTED_PUB_KEY = "0000000000000000000000000000000000000000000000000000000000000000"; uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 18; diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 3d96f6f5d..e06c3c08c 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -975,6 +975,14 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl return false; } } + else + { + // from hard fork 2, since a miner can claim less than the full block reward, we update the base_reward + // to show the amount of coins that were actually generated, the remainder will be pushed back for later + // emission. This modifies the emission curve very slightly. + CHECK_AND_ASSERT_MES(money_in_use - fee <= base_reward, false, "base reward calculation bug"); + base_reward = money_in_use - fee; + } return true; } //------------------------------------------------------------------ @@ -1093,7 +1101,7 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m block size, so first miner transaction generated with fake amount of money, and with phase we know think we know expected block size */ //make blocks coin-base tx looks close to real coinbase tx to get truthful blob size - bool r = construct_miner_tx(height, median_size, already_generated_coins, txs_size, fee, miner_address, b.miner_tx, ex_nonce, 11); + bool r = construct_miner_tx(height, median_size, already_generated_coins, txs_size, fee, miner_address, b.miner_tx, ex_nonce, 11, m_hardfork->get_current_version()); CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, first chance"); size_t cumulative_size = txs_size + get_object_blobsize(b.miner_tx); #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) @@ -1102,7 +1110,7 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m #endif for (size_t try_count = 0; try_count != 10; ++try_count) { - r = construct_miner_tx(height, median_size, already_generated_coins, cumulative_size, fee, miner_address, b.miner_tx, ex_nonce, 11); + r = construct_miner_tx(height, median_size, already_generated_coins, cumulative_size, fee, miner_address, b.miner_tx, ex_nonce, 11, m_hardfork->get_current_version()); CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, second chance"); size_t coinbase_blob_size = get_object_blobsize(b.miner_tx); @@ -1964,6 +1972,23 @@ bool Blockchain::check_tx_inputs(const transaction& tx, uint64_t& max_used_block return true; } //------------------------------------------------------------------ +bool Blockchain::check_tx_outputs(const transaction& tx) +{ + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + + // from hard fork 2, we forbid dust and compound outputs + if (m_hardfork->get_current_version() >= 2) { + BOOST_FOREACH(auto &o, tx.vout) { + if (!is_valid_decomposed_amount(o.amount)) { + return false; + } + } + } + + return true; +} +//------------------------------------------------------------------ bool Blockchain::have_tx_keyimges_as_spent(const transaction &tx) const { LOG_PRINT_L3("Blockchain::" << __func__); diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index a248682fc..3a663a342 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -134,6 +134,7 @@ namespace cryptonote bool store_blockchain(); bool check_tx_inputs(const transaction& tx, uint64_t& pmax_used_block_height, crypto::hash& max_used_block_id, bool kept_by_block = false); + bool check_tx_outputs(const transaction& tx); uint64_t get_current_cumulative_blocksize_limit() const; bool is_storing_blockchain()const{return m_is_blockchain_storing;} uint64_t block_difficulty(uint64_t i) const; diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index 979420e35..56a3dd8de 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -40,6 +40,29 @@ using namespace epee; #define ENCRYPTED_PAYMENT_ID_TAIL 0x8d +static const uint64_t valid_decomposed_outputs[] = { + (uint64_t)1, (uint64_t)2, (uint64_t)3, (uint64_t)4, (uint64_t)5, (uint64_t)6, (uint64_t)7, (uint64_t)8, (uint64_t)9, // 1 piconero + (uint64_t)10, (uint64_t)20, (uint64_t)30, (uint64_t)40, (uint64_t)50, (uint64_t)60, (uint64_t)70, (uint64_t)80, (uint64_t)90, + (uint64_t)100, (uint64_t)200, (uint64_t)300, (uint64_t)400, (uint64_t)500, (uint64_t)600, (uint64_t)700, (uint64_t)800, (uint64_t)900, + (uint64_t)1000, (uint64_t)2000, (uint64_t)3000, (uint64_t)4000, (uint64_t)5000, (uint64_t)6000, (uint64_t)7000, (uint64_t)8000, (uint64_t)9000, + (uint64_t)10000, (uint64_t)20000, (uint64_t)30000, (uint64_t)40000, (uint64_t)50000, (uint64_t)60000, (uint64_t)70000, (uint64_t)80000, (uint64_t)90000, + (uint64_t)100000, (uint64_t)200000, (uint64_t)300000, (uint64_t)400000, (uint64_t)500000, (uint64_t)600000, (uint64_t)700000, (uint64_t)800000, (uint64_t)900000, + (uint64_t)1000000, (uint64_t)2000000, (uint64_t)3000000, (uint64_t)4000000, (uint64_t)5000000, (uint64_t)6000000, (uint64_t)7000000, (uint64_t)8000000, (uint64_t)9000000, // 1 micronero + (uint64_t)10000000, (uint64_t)20000000, (uint64_t)30000000, (uint64_t)40000000, (uint64_t)50000000, (uint64_t)60000000, (uint64_t)70000000, (uint64_t)80000000, (uint64_t)90000000, + (uint64_t)100000000, (uint64_t)200000000, (uint64_t)300000000, (uint64_t)400000000, (uint64_t)500000000, (uint64_t)600000000, (uint64_t)700000000, (uint64_t)800000000, (uint64_t)900000000, + (uint64_t)1000000000, (uint64_t)2000000000, (uint64_t)3000000000, (uint64_t)4000000000, (uint64_t)5000000000, (uint64_t)6000000000, (uint64_t)7000000000, (uint64_t)8000000000, (uint64_t)9000000000, + (uint64_t)10000000000, (uint64_t)20000000000, (uint64_t)30000000000, (uint64_t)40000000000, (uint64_t)50000000000, (uint64_t)60000000000, (uint64_t)70000000000, (uint64_t)80000000000, (uint64_t)90000000000, + (uint64_t)100000000000, (uint64_t)200000000000, (uint64_t)300000000000, (uint64_t)400000000000, (uint64_t)500000000000, (uint64_t)600000000000, (uint64_t)700000000000, (uint64_t)800000000000, (uint64_t)900000000000, + (uint64_t)1000000000000, (uint64_t)2000000000000, (uint64_t)3000000000000, (uint64_t)4000000000000, (uint64_t)5000000000000, (uint64_t)6000000000000, (uint64_t)7000000000000, (uint64_t)8000000000000, (uint64_t)9000000000000, // 1 monero + (uint64_t)10000000000000, (uint64_t)20000000000000, (uint64_t)30000000000000, (uint64_t)40000000000000, (uint64_t)50000000000000, (uint64_t)60000000000000, (uint64_t)70000000000000, (uint64_t)80000000000000, (uint64_t)90000000000000, + (uint64_t)100000000000000, (uint64_t)200000000000000, (uint64_t)300000000000000, (uint64_t)400000000000000, (uint64_t)500000000000000, (uint64_t)600000000000000, (uint64_t)700000000000000, (uint64_t)800000000000000, (uint64_t)900000000000000, + (uint64_t)1000000000000000, (uint64_t)2000000000000000, (uint64_t)3000000000000000, (uint64_t)4000000000000000, (uint64_t)5000000000000000, (uint64_t)6000000000000000, (uint64_t)7000000000000000, (uint64_t)8000000000000000, (uint64_t)9000000000000000, + (uint64_t)10000000000000000, (uint64_t)20000000000000000, (uint64_t)30000000000000000, (uint64_t)40000000000000000, (uint64_t)50000000000000000, (uint64_t)60000000000000000, (uint64_t)70000000000000000, (uint64_t)80000000000000000, (uint64_t)90000000000000000, + (uint64_t)100000000000000000, (uint64_t)200000000000000000, (uint64_t)300000000000000000, (uint64_t)400000000000000000, (uint64_t)500000000000000000, (uint64_t)600000000000000000, (uint64_t)700000000000000000, (uint64_t)800000000000000000, (uint64_t)900000000000000000, + (uint64_t)1000000000000000000, (uint64_t)2000000000000000000, (uint64_t)3000000000000000000, (uint64_t)4000000000000000000, (uint64_t)5000000000000000000, (uint64_t)6000000000000000000, (uint64_t)7000000000000000000, (uint64_t)8000000000000000000, (uint64_t)9000000000000000000, // 1 meganero + (uint64_t)10000000000000000000ull +}; + namespace cryptonote { //--------------------------------------------------------------- @@ -82,7 +105,7 @@ namespace cryptonote return true; } //--------------------------------------------------------------- - bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins, size_t current_block_size, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs) { + bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins, size_t current_block_size, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version) { tx.vin.clear(); tx.vout.clear(); tx.extra.clear(); @@ -102,6 +125,15 @@ namespace cryptonote LOG_PRINT_L0("Block is too big"); return false; } + + // from hard fork 2, we cut out the low significant digits. This makes the tx smaller, and + // keeps the paid amount almost the same. The unpaid remainder gets pushed back to the + // emission schedule + if (hard_fork_version >= 2) + { + block_reward = block_reward - block_reward % ::config::BASE_REWARD_CLAMP_THRESHOLD; + } + #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) LOG_PRINT_L1("Creating block template: reward " << block_reward << ", fee " << fee) @@ -109,7 +141,7 @@ namespace cryptonote block_reward += fee; std::vector<uint64_t> out_amounts; - decompose_amount_into_digits(block_reward, ::config::DEFAULT_DUST_THRESHOLD, + decompose_amount_into_digits(block_reward, hard_fork_version >= 2 ? 0 : ::config::DEFAULT_DUST_THRESHOLD, [&out_amounts](uint64_t a_chunk) { out_amounts.push_back(a_chunk); }, [&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); }); @@ -922,4 +954,11 @@ namespace cryptonote return get_tx_tree_hash(txs_ids); } //--------------------------------------------------------------- + bool is_valid_decomposed_amount(uint64_t amount) + { + const uint64_t *begin = valid_decomposed_outputs; + const uint64_t *end = valid_decomposed_outputs + sizeof(valid_decomposed_outputs) / sizeof(valid_decomposed_outputs[0]); + return std::binary_search(begin, end, amount); + } + //--------------------------------------------------------------- } diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h index 7768500b5..202919822 100644 --- a/src/cryptonote_core/cryptonote_format_utils.h +++ b/src/cryptonote_core/cryptonote_format_utils.h @@ -44,7 +44,7 @@ namespace cryptonote crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx); bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash); bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx); - bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins, size_t current_block_size, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 1); + bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins, size_t current_block_size, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 1, uint8_t hard_fork_version = 1); bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key); bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key); @@ -231,6 +231,7 @@ namespace cryptonote void get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes, crypto::hash& h); crypto::hash get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes); crypto::hash get_tx_tree_hash(const block& b); + bool is_valid_decomposed_amount(uint64_t amount); #define CHECKED_GET_SPECIFIC_VARIANT(variant_var, specific_type, variable_name, fail_return_val) \ CHECK_AND_ASSERT_MES(variant_var.type() == typeid(specific_type), fail_return_val, "wrong variant type: " << variant_var.type().name() << ", expected " << typeid(specific_type).name()); \ diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 12fd3fe62..dce64db99 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -125,6 +125,12 @@ namespace cryptonote } } + if (!m_blockchain.check_tx_outputs(tx)) + { + LOG_PRINT_L1("Transaction with id= "<< id << " has at least one invalid outout"); + tvc.m_verifivation_failed = true; + return false; + } crypto::hash max_used_block_id = null_hash; uint64_t max_used_block_height = 0; diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index fa41e1d42..6008a9a04 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -74,7 +74,7 @@ typedef cryptonote::simple_wallet sw; unsigned int epee::g_test_dbg_lock_sleep = 0; -#define DEFAULT_MIX 3 +#define DEFAULT_MIX 4 namespace { diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 12f69e6fe..b27b303df 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1143,7 +1143,7 @@ uint64_t wallet2::select_transfers(uint64_t needed_money, bool add_dust, uint64_ const transfer_details& td = m_transfers[i]; if (!td.m_spent && is_transfer_unlocked(td)) { - if (dust < td.amount()) + if (dust < td.amount() && is_valid_decomposed_amount(td.amount())) unused_transfers_indices.push_back(i); else unused_dust_indices.push_back(i); @@ -1572,14 +1572,17 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent change_dts.amount = found_money - needed_money; } + std::vector<cryptonote::tx_destination_entry> splitted_dsts, dust_dsts; uint64_t dust = 0; - std::vector<cryptonote::tx_destination_entry> splitted_dsts; - destination_split_strategy(dsts, change_dts, dust_policy.dust_threshold, splitted_dsts, dust); - THROW_WALLET_EXCEPTION_IF(dust_policy.dust_threshold < dust, error::wallet_internal_error, "invalid dust value: dust = " + - std::to_string(dust) + ", dust_threshold = " + std::to_string(dust_policy.dust_threshold)); - if (0 != dust && !dust_policy.add_to_fee) - { - splitted_dsts.push_back(cryptonote::tx_destination_entry(dust, dust_policy.addr_for_dust)); + destination_split_strategy(dsts, change_dts, dust_policy.dust_threshold, splitted_dsts, dust_dsts); + BOOST_FOREACH(auto& d, dust_dsts) { + THROW_WALLET_EXCEPTION_IF(dust_policy.dust_threshold < d.amount, error::wallet_internal_error, "invalid dust value: dust = " + + std::to_string(d.amount) + ", dust_threshold = " + std::to_string(dust_policy.dust_threshold)); + } + BOOST_FOREACH(auto& d, dust_dsts) { + if (!dust_policy.add_to_fee) + splitted_dsts.push_back(cryptonote::tx_destination_entry(d.amount, dust_policy.addr_for_dust)); + dust += d.amount; } crypto::secret_key tx_key; @@ -1669,7 +1672,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp const transfer_details& td = m_transfers[i]; if (!td.m_spent && is_transfer_unlocked(td)) { - if (::config::DEFAULT_DUST_THRESHOLD <= td.amount()) + if (is_valid_decomposed_amount(td.amount())) unused_transfers_indices.push_back(i); else unused_dust_indices.push_back(i); @@ -1923,11 +1926,12 @@ void wallet2::transfer_dust(size_t num_outputs, uint64_t unlock_time, uint64_t n if (dust_policy.dust_threshold > 0) money_back = money_back - money_back % dust_policy.dust_threshold; dsts.push_back(cryptonote::tx_destination_entry(money_back, m_account_public_address)); - uint64_t dust = 0; - std::vector<cryptonote::tx_destination_entry> splitted_dsts; + std::vector<cryptonote::tx_destination_entry> splitted_dsts, dust; destination_split_strategy(dsts, change_dts, dust_policy.dust_threshold, splitted_dsts, dust); - THROW_WALLET_EXCEPTION_IF(dust_policy.dust_threshold < dust, error::wallet_internal_error, "invalid dust value: dust = " + - std::to_string(dust) + ", dust_threshold = " + std::to_string(dust_policy.dust_threshold)); + BOOST_FOREACH(auto& d, dust) { + THROW_WALLET_EXCEPTION_IF(dust_policy.dust_threshold < d.amount, error::wallet_internal_error, "invalid dust value: dust = " + + std::to_string(d.amount) + ", dust_threshold = " + std::to_string(dust_policy.dust_threshold)); + } crypto::secret_key tx_key; bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), sources, splitted_dsts, extra, tx, unlock_time, tx_key); @@ -1945,7 +1949,7 @@ void wallet2::transfer_dust(size_t num_outputs, uint64_t unlock_time, uint64_t n ptx.key_images = key_images; ptx.fee = money - money_back; - ptx.dust = dust; + ptx.dust = 0; ptx.tx = tx; ptx.change_dts = change_dts; ptx.selected_transfers = selected_transfers; @@ -1961,7 +1965,7 @@ std::vector<wallet2::pending_tx> wallet2::create_dust_sweep_transactions() for (transfer_container::const_iterator i = m_transfers.begin(); i != m_transfers.end(); ++i) { const transfer_details& td = *i; - if (!td.m_spent && td.amount() < dust_policy.dust_threshold && is_transfer_unlocked(td)) + if (!td.m_spent && (td.amount() < dust_policy.dust_threshold || !is_valid_decomposed_amount(td.amount())) && is_transfer_unlocked(td)) { num_dust_outputs++; } diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index b086f7ee8..0bffa7f12 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -400,48 +400,36 @@ namespace tools //---------------------------------------------------------------------------------------------------- inline void digit_split_strategy(const std::vector<cryptonote::tx_destination_entry>& dsts, const cryptonote::tx_destination_entry& change_dst, uint64_t dust_threshold, - std::vector<cryptonote::tx_destination_entry>& splitted_dsts, uint64_t& dust) + std::vector<cryptonote::tx_destination_entry>& splitted_dsts, std::vector<cryptonote::tx_destination_entry> &dust_dsts) { splitted_dsts.clear(); - dust = 0; + dust_dsts.clear(); BOOST_FOREACH(auto& de, dsts) { - cryptonote::decompose_amount_into_digits(de.amount, dust_threshold, + cryptonote::decompose_amount_into_digits(de.amount, 0, [&](uint64_t chunk) { splitted_dsts.push_back(cryptonote::tx_destination_entry(chunk, de.addr)); }, [&](uint64_t a_dust) { splitted_dsts.push_back(cryptonote::tx_destination_entry(a_dust, de.addr)); } ); } - cryptonote::decompose_amount_into_digits(change_dst.amount, dust_threshold, - [&](uint64_t chunk) { splitted_dsts.push_back(cryptonote::tx_destination_entry(chunk, change_dst.addr)); }, - [&](uint64_t a_dust) { dust = a_dust; } ); + cryptonote::decompose_amount_into_digits(change_dst.amount, 0, + [&](uint64_t chunk) { + if (chunk <= dust_threshold) + dust_dsts.push_back(cryptonote::tx_destination_entry(chunk, change_dst.addr)); + else + splitted_dsts.push_back(cryptonote::tx_destination_entry(chunk, change_dst.addr)); + }, + [&](uint64_t a_dust) { dust_dsts.push_back(cryptonote::tx_destination_entry(a_dust, change_dst.addr)); } ); } //---------------------------------------------------------------------------------------------------- inline void null_split_strategy(const std::vector<cryptonote::tx_destination_entry>& dsts, const cryptonote::tx_destination_entry& change_dst, uint64_t dust_threshold, - std::vector<cryptonote::tx_destination_entry>& splitted_dsts, uint64_t& dust) + std::vector<cryptonote::tx_destination_entry>& splitted_dsts, std::vector<cryptonote::tx_destination_entry> &dust_dsts) { splitted_dsts = dsts; - dust = 0; + dust_dsts.clear(); uint64_t change = change_dst.amount; - if (0 < dust_threshold) - { - for (uint64_t order = 10; order <= 10 * dust_threshold; order *= 10) - { - uint64_t dust_candidate = change_dst.amount % order; - uint64_t change_candidate = (change_dst.amount / order) * order; - if (dust_candidate <= dust_threshold) - { - dust = dust_candidate; - change = change_candidate; - } - else - { - break; - } - } - } if (0 != change) { @@ -577,14 +565,17 @@ namespace tools change_dts.amount = found_money - needed_money; } + std::vector<cryptonote::tx_destination_entry> splitted_dsts, dust_dsts; uint64_t dust = 0; - std::vector<cryptonote::tx_destination_entry> splitted_dsts; - destination_split_strategy(dsts, change_dts, dust_policy.dust_threshold, splitted_dsts, dust); - THROW_WALLET_EXCEPTION_IF(dust_policy.dust_threshold < dust, error::wallet_internal_error, "invalid dust value: dust = " + - std::to_string(dust) + ", dust_threshold = " + std::to_string(dust_policy.dust_threshold)); - if (0 != dust && !dust_policy.add_to_fee) - { - splitted_dsts.push_back(cryptonote::tx_destination_entry(dust, dust_policy.addr_for_dust)); + destination_split_strategy(dsts, change_dts, dust_policy.dust_threshold, splitted_dsts, dust_dsts); + BOOST_FOREACH(auto& d, dust_dsts) { + THROW_WALLET_EXCEPTION_IF(dust_policy.dust_threshold < d.amount, error::wallet_internal_error, "invalid dust value: dust = " + + std::to_string(d.amount) + ", dust_threshold = " + std::to_string(dust_policy.dust_threshold)); + } + BOOST_FOREACH(auto& d, dust_dsts) { + if (!dust_policy.add_to_fee) + splitted_dsts.push_back(cryptonote::tx_destination_entry(d.amount, dust_policy.addr_for_dust)); + dust += d.amount; } crypto::secret_key tx_key; |