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).
This commit is contained in:
moneromooo-monero 2017-03-14 19:28:38 +00:00
parent 1dfed893e0
commit 3396a9f2af
No known key found for this signature in database
GPG key ID: 686F07454D6CEFC3
10 changed files with 112 additions and 76 deletions

View file

@ -67,6 +67,15 @@ namespace cryptonote {
/* Cryptonote helper functions */ /* 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() size_t get_max_block_size()
{ {
return CRYPTONOTE_MAX_BLOCK_SIZE; return CRYPTONOTE_MAX_BLOCK_SIZE;
@ -89,7 +98,7 @@ namespace cryptonote {
base_reward = FINAL_SUBSIDY_PER_MINUTE*target_minutes; 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 //make it soft
if (median_size < full_reward_zone) { if (median_size < full_reward_zone) {

View file

@ -69,6 +69,7 @@ namespace cryptonote {
/************************************************************************/ /************************************************************************/
/* Cryptonote helper functions */ /* Cryptonote helper functions */
/************************************************************************/ /************************************************************************/
size_t get_min_block_size(uint8_t version);
size_t get_max_block_size(); size_t get_max_block_size();
size_t get_max_tx_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); bool get_block_reward(size_t median_size, size_t current_block_size, uint64_t already_generated_coins, uint64_t &reward, uint8_t version);

View file

@ -57,6 +57,7 @@
#define CRYPTONOTE_REWARD_BLOCKS_WINDOW 100 #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_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_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_COINBASE_BLOB_RESERVED_SIZE 600
#define CRYPTONOTE_DISPLAY_DECIMAL_POINT 12 #define CRYPTONOTE_DISPLAY_DECIMAL_POINT 12
// COIN - number of smallest units in one coin // COIN - number of smallest units in one coin
@ -66,6 +67,7 @@
#define FEE_PER_KB ((uint64_t)2000000000) // 2 * pow(10, 9) #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_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_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 #define ORPHANED_BLOCKS_MAX_COUNT 100
@ -128,6 +130,9 @@
#define THREAD_STACK_SIZE 5 * 1024 * 1024 #define THREAD_STACK_SIZE 5 * 1024 * 1024
#define HF_VERSION_DYNAMIC_FEE 4 #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 #define PER_KB_FEE_QUANTIZATION_DECIMALS 8
// New constants are intended to go here // New constants are intended to go here

View file

@ -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. // 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 }, { 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. // version 5 starts from block 1288616, which is on or around the 15th of april, 2017. Fork time finalised on 2016-03-14.
{ 5, 1406997, 0, 1505865600 }, { 5, 1288616, 0, 1489520158 },
}; };
static const uint64_t mainnet_hard_fork_version_1_till = 1009826; 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 n_unmixable = 0, n_mixable = 0;
size_t mixin = std::numeric_limits<size_t>::max(); size_t mixin = std::numeric_limits<size_t>::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) for (const auto& txin : tx.vin)
{ {
// non txin_to_key inputs will be rejected below // 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; tvc.m_verifivation_failed = true;
return false; 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) if (tx.version < min_tx_version)
{ {
MERROR_VER("transaction version " << (unsigned)tx.version << " is lower than min accepted 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) const uint64_t min_block_size = get_min_block_size(version);
median_block_size = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2; 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); 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 == 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<uint32_t>::max(), "DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD is too large"); static_assert(DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD / 1000000 <= std::numeric_limits<uint32_t>::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 // 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, DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD / 1000000, &hi, &lo);
div128_32(hi, lo, 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; uint64_t base_reward;
if (!get_block_reward(median, 1, already_generated_coins, base_reward, version)) if (!get_block_reward(median, 1, already_generated_coins, base_reward, version))
return false; 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"); 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) if (grace_blocks >= CRYPTONOTE_REWARD_BLOCKS_WINDOW)
grace_blocks = CRYPTONOTE_REWARD_BLOCKS_WINDOW - 1; grace_blocks = CRYPTONOTE_REWARD_BLOCKS_WINDOW - 1;
const uint64_t min_block_size = get_min_block_size(version);
std::vector<size_t> sz; std::vector<size_t> sz;
get_last_n_blocks_sizes(sz, CRYPTONOTE_REWARD_BLOCKS_WINDOW - grace_blocks); get_last_n_blocks_sizes(sz, CRYPTONOTE_REWARD_BLOCKS_WINDOW - grace_blocks);
for (size_t i = 0; i < grace_blocks; ++i) 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); uint64_t median = epee::misc_utils::median(sz);
if(median <= CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2) if(median <= min_block_size)
median = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2; 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 already_generated_coins = m_db->height() ? m_db->get_block_already_generated_coins(m_db->height() - 1) : 0;
uint64_t base_reward; 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; 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"); MDEBUG("Estimating " << grace_blocks << "-block fee at " << print_money(fee) << "/kB");
return fee; return fee;
} }
@ -3411,7 +3416,7 @@ leave:
//------------------------------------------------------------------ //------------------------------------------------------------------
bool Blockchain::update_next_cumulative_size_limit() 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__); LOG_PRINT_L3("Blockchain::" << __func__);
std::vector<size_t> sz; std::vector<size_t> sz;

View file

@ -520,10 +520,11 @@ namespace cryptonote
* *
* @param block_reward the current block reward * @param block_reward the current block reward
* @param median_block_size the median blob's size in the past window * @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 * @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 * @brief get dynamic per kB fee estimate for the next few blocks

View file

@ -59,8 +59,6 @@ namespace cryptonote
// codebase. As it stands, it is at best nontrivial to test // codebase. As it stands, it is at best nontrivial to test
// whether or not changing these parameters (or adding new) // whether or not changing these parameters (or adding new)
// will work correctly. // 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 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 time_t const MAX_RELAY_TIME = (60 * 60 * 4); // at most that many seconds between resends
float const ACCEPT_THRESHOLD = 1.0f; float const ACCEPT_THRESHOLD = 1.0f;
@ -78,6 +76,11 @@ namespace cryptonote
{ {
return amount * ACCEPT_THRESHOLD; 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; 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) if (!kept_by_block && blob_size >= tx_size_limit)
{ {
LOG_PRINT_L1("transaction is too big: " << blob_size << " bytes, maximum 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; 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, // If we're getting lower coinbase tx,
// stop including more tx // stop including more tx
uint64_t block_reward; uint64_t block_reward;
@ -666,7 +660,6 @@ namespace cryptonote
sorted_it++; sorted_it++;
continue; continue;
} }
#endif
// Skip transactions that are not ready to be // Skip transactions that are not ready to be
// included into the blockchain or that are // included into the blockchain or that are
@ -705,7 +698,7 @@ namespace cryptonote
{ {
CRITICAL_REGION_LOCAL(m_transactions_lock); CRITICAL_REGION_LOCAL(m_transactions_lock);
size_t n_removed = 0; 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(); ) { for (auto it = m_transactions.begin(); it != m_transactions.end(); ) {
if (it->second.blob_size >= tx_size_limit) { 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"); LOG_PRINT_L1("Transaction " << get_transaction_hash(it->second.tx) << " is too big (" << it->second.blob_size << " bytes), removing it from pool");

View file

@ -491,7 +491,7 @@ bool simple_wallet::set_default_priority(const std::vector<std::string> &args/*
{ {
if (strchr(args[1].c_str(), '-')) 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; return true;
} }
if (args[1] == "0") if (args[1] == "0")
@ -501,9 +501,9 @@ bool simple_wallet::set_default_priority(const std::vector<std::string> &args/*
else else
{ {
priority = boost::lexical_cast<int>(args[1]); priority = boost::lexical_cast<int>(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; return true;
} }
} }
@ -518,7 +518,7 @@ bool simple_wallet::set_default_priority(const std::vector<std::string> &args/*
} }
catch(const boost::bad_lexical_cast &) 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; return true;
} }
catch(...) 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("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("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("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 <n> - set default mixin (default is 4); auto-refresh <1|0> - whether to automatically sync new blocks from the daemon; refresh-type <full|optimize-coinbase|no-coinbase|default> - set wallet refresh behaviour; priority [1|2|3] - normal/elevated/priority fee; confirm-missing-payment-id <1|0>; ask-password <1|0>; unit <monero|millinero|micronero|nanonero|piconero> - 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 <n> - set default mixin (default is 4); auto-refresh <1|0> - whether to automatically sync new blocks from the daemon; refresh-type <full|optimize-coinbase|no-coinbase|default> - 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 <monero|millinero|micronero|nanonero|piconero> - 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("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 <txid>")); 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 <txid>"));
m_cmd_binder.set_handler("check_tx_key", boost::bind(&simple_wallet::check_tx_key, this, _1), tr("Check amount going to <address> in <txid>")); m_cmd_binder.set_handler("check_tx_key", boost::bind(&simple_wallet::check_tx_key, this, _1), tr("Check amount going to <address> in <txid>"));
@ -795,7 +795,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
{ {
if (args.size() <= 1) 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; return true;
} }
else else

View file

@ -3320,20 +3320,35 @@ bool wallet2::load_tx(const std::string &signed_filename, std::vector<tools::wal
return true; return true;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
uint64_t wallet2::get_fee_multiplier(uint32_t priority, bool use_new_fee) const uint64_t wallet2::get_fee_multiplier(uint32_t priority, int fee_algorithm) const
{ {
static const uint64_t old_multipliers[3] = {1, 2, 3}; static const uint64_t old_multipliers[3] = {1, 2, 3};
static const uint64_t new_multipliers[3] = {1, 20, 166}; static const uint64_t new_multipliers[3] = {1, 20, 166};
static const uint64_t newer_multipliers[4] = {1, 4, 20, 166};
// 0 -> default (here, x1) // 0 -> default (here, x1 till fee algorithm 2, x4 from it)
if (priority == 0) if (priority == 0)
priority = m_default_priority; priority = m_default_priority;
if (priority == 0) if (priority == 0)
{
if (fee_algorithm >= 2)
priority = 2;
else
priority = 1; priority = 1;
}
// 1 to 3 are allowed as priorities // 1 to 3/4 are allowed as priorities
if (priority >= 1 && priority <= 3) uint32_t max_priority = (fee_algorithm >= 2) ? 4 : 3;
return (use_new_fee ? new_multipliers : old_multipliers)[priority-1]; 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); THROW_WALLET_EXCEPTION_IF (false, error::invalid_priority);
return 1; return 1;
@ -3358,6 +3373,16 @@ uint64_t wallet2::get_per_kb_fee()
return get_dynamic_per_kb_fee_estimate(); 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 // separated the call(s) to wallet2::transfer into their own function
// //
// this function will make multiple calls to wallet2::transfer if multiple // this function will make multiple calls to wallet2::transfer if multiple
@ -3366,9 +3391,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<crypto
{ {
const std::vector<size_t> unused_transfers_indices = select_available_outputs_from_histogram(fake_outs_count + 1, true, true, true, trusted_daemon); const std::vector<size_t> 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_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 // failsafe split attempt counter
size_t attempt_count = 0; size_t attempt_count = 0;
@ -4147,9 +4171,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
uint64_t upper_transaction_size_limit = get_upper_tranaction_size_limit(); uint64_t upper_transaction_size_limit = get_upper_tranaction_size_limit();
const bool use_rct = use_fork_rules(4, 0); const bool use_rct = 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_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());
// throw if attempting a transaction with no destinations // throw if attempting a transaction with no destinations
THROW_WALLET_EXCEPTION_IF(dsts.empty(), error::zero_destination); THROW_WALLET_EXCEPTION_IF(dsts.empty(), error::zero_destination);
@ -4474,9 +4497,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
std::vector<std::vector<get_outs_entry>> outs; std::vector<std::vector<get_outs_entry>> outs;
const bool use_rct = fake_outs_count > 0 && use_fork_rules(4, 0); 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_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"); 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) if (m_upper_transaction_size_limit > 0)
return m_upper_transaction_size_limit; 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; return ((full_reward_zone * 125) / 100) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@ -4763,7 +4785,6 @@ std::vector<wallet2::pending_tx> wallet2::create_unmixable_sweep_transactions(bo
const bool hf1_rules = use_fork_rules(2, 10); // first hard fork has version 2 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); 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(); const uint64_t fee_per_kb = get_per_kb_fee();
// may throw // may throw

View file

@ -537,6 +537,7 @@ namespace tools
void get_hard_fork_info(uint8_t version, uint64_t &earliest_height); void get_hard_fork_info(uint8_t version, uint64_t &earliest_height);
bool use_fork_rules(uint8_t version, int64_t early_blocks = 0); 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_wallet_file() const;
std::string get_keys_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; 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(); uint64_t get_upper_tranaction_size_limit();
std::vector<uint64_t> get_unspent_amounts_vector(); std::vector<uint64_t> 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_dynamic_per_kb_fee_estimate();
uint64_t get_per_kb_fee(); uint64_t get_per_kb_fee();
float get_output_relatedness(const transfer_details &td0, const transfer_details &td1) const; float get_output_relatedness(const transfer_details &td0, const transfer_details &td1) const;

View file

@ -58,46 +58,46 @@ namespace
TEST_F(fee, 10xmr) TEST_F(fee, 10xmr)
{ {
// CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 and lower are clamped // 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, 3), 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 / 2, 3), 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, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 100, 3), clamp_fee(2000000000));
ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, 1), 2000000000); ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(10000000000000, 1, 3), 2000000000);
// higher is inverse proportional // 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 * 2, 3), 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 * 10, 3), 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 * 1000, 3), 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 * 20000ull, 3), clamp_fee(2000000000 / 20000));
} }
TEST_F(fee, 1xmr) TEST_F(fee, 1xmr)
{ {
// CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 and lower are clamped // 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, 3), 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 / 2, 3), 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, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 100, 3), clamp_fee(200000000));
ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, 1), 200000000); ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(1000000000000, 1, 3), 200000000);
// higher is inverse proportional // 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 * 2, 3), 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 * 10, 3), 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 * 1000, 3), 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 * 20000ull, 3), clamp_fee(200000000 / 20000));
} }
TEST_F(fee, dot3xmr) TEST_F(fee, dot3xmr)
{ {
// CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 and lower are clamped // 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, 3), 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 / 2, 3), 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, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 100, 3), clamp_fee(60000000));
ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, 1), 60000000); ASSERT_EQ(Blockchain::get_dynamic_per_kb_fee(300000000000, 1, 3), 60000000);
// higher is inverse proportional // 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 * 2, 3), 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 * 10, 3), 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 * 1000, 3), 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 * 20000ull, 3), clamp_fee(60000000 / 20000));
} }
static bool is_more_or_less(double x, double y) static bool is_more_or_less(double x, double y)
@ -129,7 +129,7 @@ namespace
{ {
for (uint64_t median_block_size: median_block_sizes) 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));
} }
} }
} }