From 3396a9f2aff1b4e3c12a663e0458934c8d42b32f Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Tue, 14 Mar 2017 19:28:38 +0000 Subject: [PATCH] Add intervening v5 fork for increased min block size Minimum mixin 4 and enforced ringct is moved from v5 to v6. v5 is now used for an increased minimum block size (from 60000 to 300000) to cater for larger typical/minimum transaction size. The fee algorithm is also changed to decrease the base per kB fee, and add a cheap tier for those transactions which we do not care if they get delayed (or even included in a block). --- .../cryptonote_basic_impl.cpp | 11 +++- src/cryptonote_basic/cryptonote_basic_impl.h | 1 + src/cryptonote_config.h | 5 ++ src/cryptonote_core/blockchain.cpp | 33 ++++++------ src/cryptonote_core/blockchain.h | 3 +- src/cryptonote_core/tx_pool.cpp | 21 +++----- src/simplewallet/simplewallet.cpp | 12 ++--- src/wallet/wallet2.cpp | 49 ++++++++++++------ src/wallet/wallet2.h | 3 +- tests/unit_tests/fee.cpp | 50 +++++++++---------- 10 files changed, 112 insertions(+), 76 deletions(-) diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp index 243ae4059..fb9e25c00 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.cpp +++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp @@ -67,6 +67,15 @@ namespace cryptonote { /* Cryptonote helper functions */ /************************************************************************/ //----------------------------------------------------------------------------------------------- + size_t get_min_block_size(uint8_t version) + { + if (version < 2) + return CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1; + if (version < 5) + return CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2; + return CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5; + } + //----------------------------------------------------------------------------------------------- size_t get_max_block_size() { return CRYPTONOTE_MAX_BLOCK_SIZE; @@ -89,7 +98,7 @@ namespace cryptonote { base_reward = FINAL_SUBSIDY_PER_MINUTE*target_minutes; } - uint64_t full_reward_zone = version < 2 ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1 : CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2; + uint64_t full_reward_zone = get_min_block_size(version); //make it soft if (median_size < full_reward_zone) { diff --git a/src/cryptonote_basic/cryptonote_basic_impl.h b/src/cryptonote_basic/cryptonote_basic_impl.h index 542ee6c4e..46974330b 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.h +++ b/src/cryptonote_basic/cryptonote_basic_impl.h @@ -69,6 +69,7 @@ namespace cryptonote { /************************************************************************/ /* Cryptonote helper functions */ /************************************************************************/ + size_t get_min_block_size(uint8_t version); size_t get_max_block_size(); size_t get_max_tx_size(); bool get_block_reward(size_t median_size, size_t current_block_size, uint64_t already_generated_coins, uint64_t &reward, uint8_t version); diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index d1036a1de..abfa665ff 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -57,6 +57,7 @@ #define CRYPTONOTE_REWARD_BLOCKS_WINDOW 100 #define CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 60000 //size of block (bytes) after which reward for block calculated using block size #define CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1 20000 //size of block (bytes) after which reward for block calculated using block size - before first fork +#define CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 300000 //size of block (bytes) after which reward for block calculated using block size - second change, from v5 #define CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE 600 #define CRYPTONOTE_DISPLAY_DECIMAL_POINT 12 // COIN - number of smallest units in one coin @@ -66,6 +67,7 @@ #define FEE_PER_KB ((uint64_t)2000000000) // 2 * pow(10, 9) #define DYNAMIC_FEE_PER_KB_BASE_FEE ((uint64_t)2000000000) // 2 * pow(10,9) #define DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD ((uint64_t)10000000000000) // 10 * pow(10,12) +#define DYNAMIC_FEE_PER_KB_BASE_FEE_V5 ((uint64_t)2000000000 * (uint64_t)CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5) #define ORPHANED_BLOCKS_MAX_COUNT 100 @@ -128,6 +130,9 @@ #define THREAD_STACK_SIZE 5 * 1024 * 1024 #define HF_VERSION_DYNAMIC_FEE 4 +#define HF_VERSION_MIN_MIXIN_4 6 +#define HF_VERSION_ENFORCE_RCT 6 + #define PER_KB_FEE_QUANTIZATION_DECIMALS 8 // New constants are intended to go here diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 0713274a6..5f8db45ad 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -97,8 +97,8 @@ static const struct { // version 4 starts from block 1220516, which is on or around the 5th of January, 2017. Fork time finalised on 2016-09-18. { 4, 1220516, 0, 1483574400 }, - // version 5 starts from block 1406997, which is on or around the 20th of September, 2017. Fork time finalised on 2016-09-18. - { 5, 1406997, 0, 1505865600 }, + // version 5 starts from block 1288616, which is on or around the 15th of april, 2017. Fork time finalised on 2016-03-14. + { 5, 1288616, 0, 1489520158 }, }; static const uint64_t mainnet_hard_fork_version_1_till = 1009826; @@ -2426,7 +2426,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, { size_t n_unmixable = 0, n_mixable = 0; size_t mixin = std::numeric_limits::max(); - const size_t min_mixin = hf_version >= 5 ? 4 : 2; + const size_t min_mixin = hf_version >= HF_VERSION_MIN_MIXIN_4 ? 4 : 2; for (const auto& txin : tx.vin) { // non txin_to_key inputs will be rejected below @@ -2479,7 +2479,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, tvc.m_verifivation_failed = true; return false; } - const size_t min_tx_version = (n_unmixable > 0 ? 1 : (hf_version >= 5) ? 2 : 1); + const size_t min_tx_version = (n_unmixable > 0 ? 1 : (hf_version >= HF_VERSION_ENFORCE_RCT) ? 2 : 1); if (tx.version < min_tx_version) { MERROR_VER("transaction version " << (unsigned)tx.version << " is lower than min accepted version " << min_tx_version); @@ -2809,15 +2809,19 @@ static uint64_t get_fee_quantization_mask() } //------------------------------------------------------------------ -uint64_t Blockchain::get_dynamic_per_kb_fee(uint64_t block_reward, size_t median_block_size) +uint64_t Blockchain::get_dynamic_per_kb_fee(uint64_t block_reward, size_t median_block_size, uint8_t version) { - if (median_block_size < CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2) - median_block_size = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2; + const uint64_t min_block_size = get_min_block_size(version); + const uint64_t fee_per_kb_base = version >= 5 ? DYNAMIC_FEE_PER_KB_BASE_FEE_V5 : DYNAMIC_FEE_PER_KB_BASE_FEE; - uint64_t unscaled_fee_per_kb = (DYNAMIC_FEE_PER_KB_BASE_FEE * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / median_block_size); + if (median_block_size < min_block_size) + median_block_size = min_block_size; + + uint64_t unscaled_fee_per_kb = (fee_per_kb_base * min_block_size / median_block_size); uint64_t hi, lo = mul128(unscaled_fee_per_kb, block_reward, &hi); static_assert(DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD % 1000000 == 0, "DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD must be divisible by 1000000"); static_assert(DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD / 1000000 <= std::numeric_limits::max(), "DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD is too large"); + // divide in two steps, since the divisor must be 32 bits, but DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD isn't div128_32(hi, lo, DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD / 1000000, &hi, &lo); div128_32(hi, lo, 1000000, &hi, &lo); @@ -2848,7 +2852,7 @@ bool Blockchain::check_fee(size_t blob_size, uint64_t fee) const uint64_t base_reward; if (!get_block_reward(median, 1, already_generated_coins, base_reward, version)) return false; - fee_per_kb = get_dynamic_per_kb_fee(base_reward, median); + fee_per_kb = get_dynamic_per_kb_fee(base_reward, median, version); } MDEBUG("Using " << print_money(fee) << "/kB fee"); @@ -2875,14 +2879,15 @@ uint64_t Blockchain::get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks) cons if (grace_blocks >= CRYPTONOTE_REWARD_BLOCKS_WINDOW) grace_blocks = CRYPTONOTE_REWARD_BLOCKS_WINDOW - 1; + const uint64_t min_block_size = get_min_block_size(version); std::vector sz; get_last_n_blocks_sizes(sz, CRYPTONOTE_REWARD_BLOCKS_WINDOW - grace_blocks); for (size_t i = 0; i < grace_blocks; ++i) - sz.push_back(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2); + sz.push_back(min_block_size); uint64_t median = epee::misc_utils::median(sz); - if(median <= CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2) - median = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2; + if(median <= min_block_size) + median = min_block_size; uint64_t already_generated_coins = m_db->height() ? m_db->get_block_already_generated_coins(m_db->height() - 1) : 0; uint64_t base_reward; @@ -2892,7 +2897,7 @@ uint64_t Blockchain::get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks) cons base_reward = BLOCK_REWARD_OVERESTIMATE; } - uint64_t fee = get_dynamic_per_kb_fee(base_reward, median); + uint64_t fee = get_dynamic_per_kb_fee(base_reward, median, version); MDEBUG("Estimating " << grace_blocks << "-block fee at " << print_money(fee) << "/kB"); return fee; } @@ -3411,7 +3416,7 @@ leave: //------------------------------------------------------------------ bool Blockchain::update_next_cumulative_size_limit() { - uint64_t full_reward_zone = get_current_hard_fork_version() < 2 ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1 : CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2; + uint64_t full_reward_zone = get_min_block_size(get_current_hard_fork_version()); LOG_PRINT_L3("Blockchain::" << __func__); std::vector sz; diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 2c7420e18..7dac608c1 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -520,10 +520,11 @@ namespace cryptonote * * @param block_reward the current block reward * @param median_block_size the median blob's size in the past window + * @param version hard fork version for rules and constants to use * * @return the per kB fee */ - static uint64_t get_dynamic_per_kb_fee(uint64_t block_reward, size_t median_block_size); + static uint64_t get_dynamic_per_kb_fee(uint64_t block_reward, size_t median_block_size, uint8_t version); /** * @brief get dynamic per kB fee estimate for the next few blocks diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index e943c961d..4dd2832ac 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -59,8 +59,6 @@ namespace cryptonote // codebase. As it stands, it is at best nontrivial to test // whether or not changing these parameters (or adding new) // will work correctly. - size_t const TRANSACTION_SIZE_LIMIT_V1 = (((CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1 * 125) / 100) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE); - size_t const TRANSACTION_SIZE_LIMIT_V2 = (((CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 125) / 100) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE); time_t const MIN_RELAY_TIME = (60 * 5); // only start re-relaying transactions after that many seconds time_t const MAX_RELAY_TIME = (60 * 60 * 4); // at most that many seconds between resends float const ACCEPT_THRESHOLD = 1.0f; @@ -78,6 +76,11 @@ namespace cryptonote { return amount * ACCEPT_THRESHOLD; } + + uint64_t get_transaction_size_limit(uint8_t version) + { + return get_min_block_size(version) * 125 / 100 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; + } } //--------------------------------------------------------------------------------- //--------------------------------------------------------------------------------- @@ -149,7 +152,7 @@ namespace cryptonote return false; } - size_t tx_size_limit = (version < 2 ? TRANSACTION_SIZE_LIMIT_V1 : TRANSACTION_SIZE_LIMIT_V2); + size_t tx_size_limit = get_transaction_size_limit(version); if (!kept_by_block && blob_size >= tx_size_limit) { LOG_PRINT_L1("transaction is too big: " << blob_size << " bytes, maximum size: " << tx_size_limit); @@ -641,15 +644,6 @@ namespace cryptonote continue; } -#if 1 - // If we've exceeded the penalty free size, - // stop including more tx - if (total_size > median_size) - { - LOG_PRINT_L2(" would exceed median block size"); - break; - } -#else // If we're getting lower coinbase tx, // stop including more tx uint64_t block_reward; @@ -666,7 +660,6 @@ namespace cryptonote sorted_it++; continue; } -#endif // Skip transactions that are not ready to be // included into the blockchain or that are @@ -705,7 +698,7 @@ namespace cryptonote { CRITICAL_REGION_LOCAL(m_transactions_lock); size_t n_removed = 0; - size_t tx_size_limit = (version < 2 ? TRANSACTION_SIZE_LIMIT_V1 : TRANSACTION_SIZE_LIMIT_V2); + size_t tx_size_limit = get_transaction_size_limit(version); for (auto it = m_transactions.begin(); it != m_transactions.end(); ) { if (it->second.blob_size >= tx_size_limit) { LOG_PRINT_L1("Transaction " << get_transaction_hash(it->second.tx) << " is too big (" << it->second.blob_size << " bytes), removing it from pool"); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 727103fa8..f5763648f 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -491,7 +491,7 @@ bool simple_wallet::set_default_priority(const std::vector &args/* { if (strchr(args[1].c_str(), '-')) { - fail_msg_writer() << tr("priority must be 0, 1, 2, or 3 "); + fail_msg_writer() << tr("priority must be 0, 1, 2, 3, or 4 "); return true; } if (args[1] == "0") @@ -501,9 +501,9 @@ bool simple_wallet::set_default_priority(const std::vector &args/* else { priority = boost::lexical_cast(args[1]); - if (priority != 1 && priority != 2 && priority != 3) + if (priority < 1 || priority > 4) { - fail_msg_writer() << tr("priority must be 0, 1, 2, or 3"); + fail_msg_writer() << tr("priority must be 0, 1, 2, 3,or 4"); return true; } } @@ -518,7 +518,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 or 3"); + fail_msg_writer() << tr("priority must be 0, 1, 2 3,or 4"); return true; } catch(...) @@ -659,7 +659,7 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("viewkey", boost::bind(&simple_wallet::viewkey, this, _1), tr("Display private view key")); m_cmd_binder.set_handler("spendkey", boost::bind(&simple_wallet::spendkey, this, _1), tr("Display private spend key")); m_cmd_binder.set_handler("seed", boost::bind(&simple_wallet::seed, this, _1), tr("Display Electrum-style mnemonic seed")); - m_cmd_binder.set_handler("set", boost::bind(&simple_wallet::set_variable, this, _1), tr("Available options: seed language - set wallet seed language; always-confirm-transfers <1|0> - whether to confirm unsplit txes; print-ring-members <1|0> - whether to print detailed information about ring members during confirmation; store-tx-info <1|0> - whether to store outgoing tx info (destination address, payment ID, tx secret key) for future reference; default-mixin - set default mixin (default is 4); auto-refresh <1|0> - whether to automatically sync new blocks from the daemon; refresh-type - set wallet refresh behaviour; priority [1|2|3] - normal/elevated/priority fee; confirm-missing-payment-id <1|0>; ask-password <1|0>; unit - set default monero (sub-)unit")); + m_cmd_binder.set_handler("set", boost::bind(&simple_wallet::set_variable, this, _1), tr("Available options: seed language - set wallet seed language; always-confirm-transfers <1|0> - whether to confirm unsplit txes; print-ring-members <1|0> - whether to print detailed information about ring members during confirmation; store-tx-info <1|0> - whether to store outgoing tx info (destination address, payment ID, tx secret key) for future reference; default-mixin - set default mixin (default is 4); auto-refresh <1|0> - whether to automatically sync new blocks from the daemon; refresh-type - set wallet refresh behaviour; priority [0|1|2|3|4] - default/unimportant/normal/elevated/priority fee; confirm-missing-payment-id <1|0>; ask-password <1|0>; unit - set default monero (sub-)unit")); m_cmd_binder.set_handler("rescan_spent", boost::bind(&simple_wallet::rescan_spent, this, _1), tr("Rescan blockchain for spent outputs")); m_cmd_binder.set_handler("get_tx_key", boost::bind(&simple_wallet::get_tx_key, this, _1), tr("Get transaction key (r) for a given ")); m_cmd_binder.set_handler("check_tx_key", boost::bind(&simple_wallet::check_tx_key, this, _1), tr("Check amount going to
in ")); @@ -795,7 +795,7 @@ bool simple_wallet::set_variable(const std::vector &args) { if (args.size() <= 1) { - fail_msg_writer() << tr("set priority: needs an argument: 0, 1, 2, or 3"); + fail_msg_writer() << tr("set priority: needs an argument: 0, 1, 2, 3, or 4"); return true; } else diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 7ae2ce074..379159709 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3320,20 +3320,35 @@ bool wallet2::load_tx(const std::string &signed_filename, std::vector default (here, x1) + // 0 -> default (here, x1 till fee algorithm 2, x4 from it) if (priority == 0) priority = m_default_priority; if (priority == 0) - priority = 1; + { + if (fee_algorithm >= 2) + priority = 2; + else + priority = 1; + } - // 1 to 3 are allowed as priorities - if (priority >= 1 && priority <= 3) - return (use_new_fee ? new_multipliers : old_multipliers)[priority-1]; + // 1 to 3/4 are allowed as priorities + uint32_t max_priority = (fee_algorithm >= 2) ? 4 : 3; + if (priority >= 1 && priority <= max_priority) + { + switch (fee_algorithm) + { + case 0: return old_multipliers[priority-1]; + case 1: return new_multipliers[priority-1]; + case 2: return newer_multipliers[priority-1]; + default: THROW_WALLET_EXCEPTION_IF (true, error::invalid_priority); + } + } THROW_WALLET_EXCEPTION_IF (false, error::invalid_priority); return 1; @@ -3358,6 +3373,16 @@ uint64_t wallet2::get_per_kb_fee() return get_dynamic_per_kb_fee_estimate(); } //---------------------------------------------------------------------------------------------------- +int wallet2::get_fee_algorithm() +{ + // changes at v3 and v5 + if (use_fork_rules(5, -720 * 14)) + return 2; + if (use_fork_rules(3, -720 * 14)) + return 1; + return 0; +} +//---------------------------------------------------------------------------------------------------- // separated the call(s) to wallet2::transfer into their own function // // this function will make multiple calls to wallet2::transfer if multiple @@ -3366,9 +3391,8 @@ std::vector wallet2::create_transactions(std::vector unused_transfers_indices = select_available_outputs_from_histogram(fake_outs_count + 1, true, true, true, trusted_daemon); - const bool use_new_fee = use_fork_rules(3, -720 * 14); const uint64_t fee_per_kb = get_per_kb_fee(); - const uint64_t fee_multiplier = get_fee_multiplier(priority, use_new_fee); + const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm()); // failsafe split attempt counter size_t attempt_count = 0; @@ -4147,9 +4171,8 @@ std::vector wallet2::create_transactions_2(std::vector wallet2::create_transactions_from(const crypton std::vector> outs; const bool use_rct = fake_outs_count > 0 && use_fork_rules(4, 0); - const bool use_new_fee = use_fork_rules(3, -720 * 14); const uint64_t fee_per_kb = get_per_kb_fee(); - const uint64_t fee_multiplier = get_fee_multiplier(priority, use_new_fee); + const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm()); LOG_PRINT_L2("Starting with " << unused_transfers_indices.size() << " non-dust outputs and " << unused_dust_indices.size() << " dust outputs"); @@ -4637,7 +4659,7 @@ uint64_t wallet2::get_upper_tranaction_size_limit() { if (m_upper_transaction_size_limit > 0) return m_upper_transaction_size_limit; - uint64_t full_reward_zone = use_fork_rules(2, 10) ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 : CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1; + uint64_t full_reward_zone = use_fork_rules(5, 10) ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : use_fork_rules(2, 10) ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 : CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1; return ((full_reward_zone * 125) / 100) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; } //---------------------------------------------------------------------------------------------------- @@ -4763,7 +4785,6 @@ std::vector wallet2::create_unmixable_sweep_transactions(bo const bool hf1_rules = use_fork_rules(2, 10); // first hard fork has version 2 tx_dust_policy dust_policy(hf1_rules ? 0 : ::config::DEFAULT_DUST_THRESHOLD); - const bool use_new_fee = use_fork_rules(3, -720 * 14); const uint64_t fee_per_kb = get_per_kb_fee(); // may throw diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index ddc237f1b..5c8d0ae86 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -537,6 +537,7 @@ namespace tools void get_hard_fork_info(uint8_t version, uint64_t &earliest_height); bool use_fork_rules(uint8_t version, int64_t early_blocks = 0); + int get_fee_algorithm(); std::string get_wallet_file() const; std::string get_keys_file() const; @@ -622,7 +623,7 @@ namespace tools void parse_block_round(const cryptonote::blobdata &blob, cryptonote::block &bl, crypto::hash &bl_id, bool &error) const; uint64_t get_upper_tranaction_size_limit(); std::vector get_unspent_amounts_vector(); - uint64_t get_fee_multiplier(uint32_t priority, bool use_new_fee) const; + uint64_t get_fee_multiplier(uint32_t priority, int fee_algorithm) const; uint64_t get_dynamic_per_kb_fee_estimate(); uint64_t get_per_kb_fee(); float get_output_relatedness(const transfer_details &td0, const transfer_details &td1) const; diff --git a/tests/unit_tests/fee.cpp b/tests/unit_tests/fee.cpp index 7026aec5c..3013a8c0c 100644 --- a/tests/unit_tests/fee.cpp +++ b/tests/unit_tests/fee.cpp @@ -58,46 +58,46 @@ namespace TEST_F(fee, 10xmr) { // CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 and lower are clamped - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2), clamp_fee(2000000000)); - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 2), clamp_fee(2000000000)); - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 100), clamp_fee(2000000000)); - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, 1), 2000000000); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2, 3), clamp_fee(2000000000)); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 2, 3), clamp_fee(2000000000)); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 100, 3), clamp_fee(2000000000)); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, 1, 3), 2000000000); // higher is inverse proportional - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 2), clamp_fee(2000000000 / 2)); - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 10), clamp_fee(2000000000 / 10)); - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 1000), clamp_fee(2000000000 / 1000)); - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 20000ull), clamp_fee(2000000000 / 20000)); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 2, 3), clamp_fee(2000000000 / 2)); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 10, 3), clamp_fee(2000000000 / 10)); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 1000, 3), clamp_fee(2000000000 / 1000)); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 20000ull, 3), clamp_fee(2000000000 / 20000)); } TEST_F(fee, 1xmr) { // CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 and lower are clamped - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2), clamp_fee(200000000)); - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 2), clamp_fee(200000000)); - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 100), clamp_fee(200000000)); - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, 1), 200000000); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2, 3), clamp_fee(200000000)); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 2, 3), clamp_fee(200000000)); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 100, 3), clamp_fee(200000000)); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, 1, 3), 200000000); // higher is inverse proportional - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 2), clamp_fee(200000000 / 2)); - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 10), clamp_fee(200000000 / 10)); - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 1000), clamp_fee(200000000 / 1000)); - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 20000ull), clamp_fee(200000000 / 20000)); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 2, 3), clamp_fee(200000000 / 2)); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 10, 3), clamp_fee(200000000 / 10)); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 1000, 3), clamp_fee(200000000 / 1000)); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 20000ull, 3), clamp_fee(200000000 / 20000)); } TEST_F(fee, dot3xmr) { // CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 and lower are clamped - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2), clamp_fee(60000000)); - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 2), clamp_fee(60000000)); - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 100), clamp_fee(60000000)); - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, 1), 60000000); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2, 3), clamp_fee(60000000)); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 2, 3), clamp_fee(60000000)); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 100, 3), clamp_fee(60000000)); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, 1, 3), 60000000); // higher is inverse proportional - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 2), clamp_fee(60000000 / 2)); - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 10), clamp_fee(60000000 / 10)); - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 1000), clamp_fee(60000000 / 1000)); - ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 20000ull), clamp_fee(60000000 / 20000)); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 2, 3), clamp_fee(60000000 / 2)); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 10, 3), clamp_fee(60000000 / 10)); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 1000, 3), clamp_fee(60000000 / 1000)); + ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 20000ull, 3), clamp_fee(60000000 / 20000)); } static bool is_more_or_less(double x, double y) @@ -129,7 +129,7 @@ namespace { for (uint64_t median_block_size: median_block_sizes) { - ASSERT_TRUE(is_more_or_less(Blockchain::get_dynamic_per_kb_fee(block_reward, median_block_size) * (median_block_size / 1024.) * MAX_MULTIPLIER / (double)block_reward, 1.992 * 1000 / 1024)); + ASSERT_TRUE(is_more_or_less(Blockchain::get_dynamic_per_kb_fee(block_reward, median_block_size, 3) * (median_block_size / 1024.) * MAX_MULTIPLIER / (double)block_reward, 1.992 * 1000 / 1024)); } } }