Lower blink fees, remove higher priorities and backlog checking

This reduces blink fees by half (from 5x to 2.5x base fee) at HF15, and
makes anything other than "unimportant" priority map to blink for
ordinary transactions.

For non-blink txes priorities are still accepted (so that, if the
mempool is clogged, you can still get a registration or stake through by
upping the priority).

It also updates the wallets default priority for transactions to blink
(that is, "default" now becomes blink).

With the priorities gone and default set to blink, the backlog-checking
code and automatic priority bumping code don't serve any useful purpose,
so this rips them out, along with a few other related code
simplifications.
This commit is contained in:
Jason Rhinelander 2020-02-18 17:47:37 -04:00
parent 228fcdb493
commit 0b0e909d8f
9 changed files with 91 additions and 403 deletions

View File

@ -102,7 +102,11 @@ static_assert(STAKING_PORTIONS % 12 == 0, "Use a multiple of twelve, so that it
// and the miner including the tx includes MINER_TX_FEE_PERCENT * [minimum tx fee]; the rest must be left unclaimed.
#define BLINK_MINER_TX_FEE_PERCENT 100 // The blink miner tx fee (as a percentage of the minimum tx fee)
#define BLINK_BURN_FIXED 0 // A fixed amount (in atomic currency units) that the sender must burn
#define BLINK_BURN_TX_FEE_PERCENT 400 // A percentage of the minimum miner tx fee that the sender must burn. (Adds to BLINK_BURN_FIXED)
#define BLINK_BURN_TX_FEE_PERCENT 150 // A percentage of the minimum miner tx fee that the sender must burn. (Adds to BLINK_BURN_FIXED)
// FIXME: can remove this post-fork 15; the burned amount only matters for mempool acceptance and
// blink quorum signing, but isn't part of the blockchain concensus rules (so we don't actually have
// to keep it around in the code for syncing the chain).
#define BLINK_BURN_TX_FEE_PERCENT_OLD 400 // A percentage of the minimum miner tx fee that the sender must burn. (Adds to BLINK_BURN_FIXED)
static_assert(BLINK_MINER_TX_FEE_PERCENT >= 100, "blink miner fee cannot be smaller than the base tx fee");
static_assert(BLINK_BURN_FIXED >= 0, "fixed blink burn amount cannot be negative");

View File

@ -522,7 +522,7 @@ namespace cryptonote
bool approved = blink.approved();
auto hf_version = m_blockchain.get_ideal_hard_fork_version(blink.height);
bool result = add_tx(tx, tvc, tx_pool_options::new_blink(approved), hf_version);
bool result = add_tx(tx, tvc, tx_pool_options::new_blink(approved, hf_version), hf_version);
if (result && approved)
{
auto lock = blink_unique_lock();

View File

@ -87,12 +87,12 @@ namespace cryptonote
static tx_pool_options from_block() { tx_pool_options o; o.kept_by_block = true; o.relayed = true; return o; }
static tx_pool_options from_peer() { tx_pool_options o; o.relayed = true; return o; }
static tx_pool_options new_tx(bool do_not_relay = false) { tx_pool_options o; o.do_not_relay = do_not_relay; return o; }
static tx_pool_options new_blink(bool approved) {
static tx_pool_options new_blink(bool approved, uint8_t hf_version) {
tx_pool_options o;
o.do_not_relay = !approved;
o.approved_blink = approved;
o.fee_percent = BLINK_MINER_TX_FEE_PERCENT;
o.burn_percent = BLINK_BURN_TX_FEE_PERCENT;
o.burn_percent = hf_version <= network_version_14_blink ? BLINK_BURN_TX_FEE_PERCENT_OLD : BLINK_BURN_TX_FEE_PERCENT;
o.burn_fixed = BLINK_BURN_FIXED;
return o;
}

View File

@ -174,12 +174,12 @@ namespace
const char* USAGE_INCOMING_TRANSFERS("incoming_transfers [available|unavailable] [verbose] [uses] [index=<N1>[,<N2>[,...]]]");
const char* USAGE_PAYMENTS("payments <PID_1> [<PID_2> ... <PID_N>]");
const char* USAGE_PAYMENT_ID("payment_id");
const char* USAGE_TRANSFER("transfer [index=<N1>[,<N2>,...]] [blink|<priority>] (<URI> | <address> <amount>) [<payment_id>]");
const char* USAGE_TRANSFER("transfer [index=<N1>[,<N2>,...]] [blink|unimportant] (<URI> | <address> <amount>) [<payment_id>]");
const char* USAGE_LOCKED_TRANSFER("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] (<URI> | <addr> <amount>) <lockblocks> [<payment_id (obsolete)>]");
const char* USAGE_LOCKED_SWEEP_ALL("locked_sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<address>] <lockblocks> [<payment_id (obsolete)>]");
const char* USAGE_SWEEP_ALL("sweep_all [index=<N1>[,<N2>,...]] [blink|<priority>] [outputs=<N>] [<address> [<payment_id (obsolete)>]] [use_v1_tx]");
const char* USAGE_SWEEP_BELOW("sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [blink|<priority>] [<address> [<payment_id (obsolete)>]]");
const char* USAGE_SWEEP_SINGLE("sweep_single [blink|<priority>] [outputs=<N>] <key_image> <address> [<payment_id (obsolete)>]");
const char* USAGE_SWEEP_ALL("sweep_all [index=<N1>[,<N2>,...]] [blink|unimportant] [outputs=<N>] [<address> [<payment_id (obsolete)>]] [use_v1_tx]");
const char* USAGE_SWEEP_BELOW("sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [blink|unimportant] [<address> [<payment_id (obsolete)>]]");
const char* USAGE_SWEEP_SINGLE("sweep_single [blink|unimportant] [outputs=<N>] <key_image> <address> [<payment_id (obsolete)>]");
const char* USAGE_SIGN_TRANSFER("sign_transfer [export_raw]");
const char* USAGE_SET_LOG("set_log <level>|{+,-,}<categories>");
const char* USAGE_ACCOUNT("account\n"
@ -916,59 +916,21 @@ bool simple_wallet::print_fee_info(const std::vector<std::string> &args/* = std:
return true;
const auto base_fee = m_wallet->get_base_fees();
const uint64_t typical_size = 2500, typical_outs = 2;
message_writer() << (boost::format(tr("Current fee is %s %s per byte + %s %s per output")) %
message_writer() << (boost::format(tr("Current base fee is %s %s per byte + %s %s per output")) %
print_money(base_fee.first) % cryptonote::get_unit(cryptonote::get_default_decimal_point()) %
print_money(base_fee.second) % cryptonote::get_unit(cryptonote::get_default_decimal_point())).str();
std::vector<uint64_t> fees;
std::ostringstream typical_fees;
for (uint32_t priority = 1; priority <= 4; ++priority)
{
uint64_t pct = m_wallet->get_fee_percent(priority);
uint64_t typical_fee = (base_fee.first * typical_size + base_fee.second * typical_outs) * pct / 100;
fees.push_back(typical_fee);
if (priority > 1) typical_fees << ", ";
typical_fees << print_money(typical_fee) << " (" << tools::allowed_priority_strings[priority] << ")";
}
std::vector<std::pair<uint64_t, uint64_t>> blocks;
try
{
blocks = m_wallet->estimate_backlog(typical_size, typical_size, fees);
}
catch (const std::exception &e)
{
fail_msg_writer() << tr("Error: failed to estimate backlog array size: ") << e.what();
return true;
}
if (blocks.size() != 4)
{
fail_msg_writer() << tr("Error: bad estimated backlog array size");
return true;
}
for (uint32_t priority = 1; priority <= 4; ++priority)
{
uint64_t nblocks_low = blocks[priority - 1].first;
uint64_t nblocks_high = blocks[priority - 1].second;
if (nblocks_low > 0)
{
std::string msg;
if (priority == m_wallet->get_default_priority() || (m_wallet->get_default_priority() == 0 && priority == 2))
msg = tr(" (current)");
uint64_t minutes_low = nblocks_low * DIFFICULTY_TARGET_V2 / 60, minutes_high = nblocks_high * DIFFICULTY_TARGET_V2 / 60;
if (nblocks_high == nblocks_low)
message_writer() << (boost::format(tr("%u block (%u minutes) backlog at priority %u%s")) % nblocks_low % minutes_low % priority % msg).str();
else
message_writer() << (boost::format(tr("%u to %u block (%u to %u minutes) backlog at priority %u")) % nblocks_low % nblocks_high % minutes_low % minutes_high % priority).str();
}
else
message_writer() << tr("No backlog at priority ") << priority;
}
uint64_t pct = m_wallet->get_fee_percent(1, txtype::standard);
uint64_t typical_fee = (base_fee.first * typical_size + base_fee.second * typical_outs) * pct / 100;
fees.push_back(typical_fee);
typical_fees << print_money(typical_fee) << " (" << tools::allowed_priority_strings[1] << ")";
auto hf_version = m_wallet->get_hard_fork_version();
if (hf_version && *hf_version >= HF_VERSION_BLINK)
{
uint64_t pct = m_wallet->get_fee_percent(tools::tx_priority_blink);
uint64_t pct = m_wallet->get_fee_percent(tools::tx_priority_blink, txtype::standard);
uint64_t fixed = BLINK_BURN_FIXED;
uint64_t typical_blink_fee = (base_fee.first * typical_size + base_fee.second * typical_outs) * pct / 100 + fixed;
@ -2276,40 +2238,22 @@ bool simple_wallet::set_store_tx_info(const std::vector<std::string> &args/* = s
bool simple_wallet::set_default_priority(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
uint32_t priority = 0;
try
int priority = -1;
if (args[1].size() == 1 && args[1][0] >= '0' && args[1][0] <= '5')
priority = args[1][0] - '0';
else
{
if (strchr(args[1].c_str(), '-'))
{
fail_msg_writer() << tr("priority must be either 0, 1, 2, 3, or 4, or one of: ") << join_priority_strings(", ");
return true;
}
if (args[1] == "0")
{
priority = 0;
}
else
{
bool found = false;
for (size_t n = 0; n < tools::allowed_priority_strings.size(); ++n)
{
if (tools::allowed_priority_strings[n] == args[1])
{
found = true;
priority = n;
}
}
if (!found)
{
priority = boost::lexical_cast<int>(args[1]);
if (priority < 1 || priority > 4)
{
fail_msg_writer() << tr("priority must be either 0, 1, 2, 3, or 4, or one of: ") << join_priority_strings(", ");
return true;
}
}
}
auto it = std::find(tools::allowed_priority_strings.begin(), tools::allowed_priority_strings.end(), args[1]);
if (it != tools::allowed_priority_strings.end())
priority = it - tools::allowed_priority_strings.begin();
}
if (priority == -1)
{
fail_msg_writer() << tr("priority must be a 0-5 value or one of: ") << join_priority_strings(", ");
return true;
}
try {
const auto pwd_container = get_and_verify_password();
if (pwd_container)
{
@ -2318,11 +2262,6 @@ bool simple_wallet::set_default_priority(const std::vector<std::string> &args/*
}
return true;
}
catch(const boost::bad_lexical_cast &)
{
fail_msg_writer() << tr("priority must be either 0, 1, 2, 3, or 4, or one of: ") << join_priority_strings(", ");
return true;
}
catch(...)
{
fail_msg_writer() << tr("could not change default priority");
@ -2475,37 +2414,6 @@ bool simple_wallet::set_merge_destinations(const std::vector<std::string> &args/
return true;
}
bool simple_wallet::set_confirm_backlog(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
const auto pwd_container = get_and_verify_password();
if (pwd_container)
{
parse_bool_and_use(args[1], [&](bool r) {
m_wallet->confirm_backlog(r);
m_wallet->rewrite(m_wallet_file, pwd_container->password());
});
}
return true;
}
bool simple_wallet::set_confirm_backlog_threshold(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
uint32_t threshold;
if (!string_tools::get_xtype_from_string(threshold, args[1]))
{
fail_msg_writer() << tr("invalid count: must be an unsigned integer");
return true;
}
const auto pwd_container = get_and_verify_password();
if (pwd_container)
{
m_wallet->set_confirm_backlog_threshold(threshold);
m_wallet->rewrite(m_wallet_file, pwd_container->password());
}
return true;
}
bool simple_wallet::set_confirm_export_overwrite(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
const auto pwd_container = get_and_verify_password();
@ -2536,19 +2444,6 @@ bool simple_wallet::set_refresh_from_block_height(const std::vector<std::string>
return true;
}
bool simple_wallet::set_auto_low_priority(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
const auto pwd_container = get_and_verify_password();
if (pwd_container)
{
parse_bool_and_use(args[1], [&](bool r) {
m_wallet->auto_low_priority(r);
m_wallet->rewrite(m_wallet_file, pwd_container->password());
});
}
return true;
}
bool simple_wallet::set_segregate_pre_fork_outputs(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
const auto pwd_container = get_and_verify_password();
@ -2841,10 +2736,13 @@ simple_wallet::simple_wallet()
Whether to automatically synchronize new blocks from the daemon.
refresh-type <full|optimize-coinbase|no-coinbase|default>
Set the wallet's refresh behaviour.
priority [0|1|2|3|4]
Set the fee to default/unimportant/normal/elevated/priority.
priority <0|1|2|3|4|5>
priority <default|unimportant|normal|elevated|priority|blink>
Set the default transaction priority to the given numeric or string value. Note that
for ordinary transactions, all values other than 1/"unimportant" will result in blink
transactions.
ask-password <0|1|2>
(or never|action|decrypt)>
ask-password <never|action|decrypt>
action: ask the password before many actions such as transfer, etc
decrypt: same as action, but keeps the spend key encrypted in memory when not needed
unit <loki|megarok|kilorok|rok>
@ -2863,7 +2761,6 @@ simple_wallet::simple_wallet()
Set this if you are not sure whether you will spend on a key reusing Loki fork later.
subaddress-lookahead <major>:<minor>
Set the lookahead sizes for the subaddress hash table.
Set this if you are not sure whether you will spend on a key reusing Loki fork later.
segregation-height <n>
Set to the height of a key reusing fork you want to use, 0 to use default.)"));
@ -3004,7 +2901,7 @@ Pending or Failed: "failed"|"pending", "out", Time, Amount*, Transaction Hash,
tr("Generate a new random full size payment id (obsolete). These will be unencrypted on the blockchain, see integrated_address for encrypted short payment ids."));
m_cmd_binder.set_handler("fee",
boost::bind(&simple_wallet::print_fee_info, this, _1),
tr("Print the information about the current fee and transaction backlog."));
tr("Print information about the current transaction fees."));
m_cmd_binder.set_handler("prepare_multisig", boost::bind(&simple_wallet::prepare_multisig, this, _1),
tr("Export data needed to create a multisig wallet"));
m_cmd_binder.set_handler("make_multisig", boost::bind(&simple_wallet::make_multisig, this, _1),
@ -3259,11 +3156,8 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
success_msg_writer() << "min-outputs-count = " << m_wallet->get_min_output_count();
success_msg_writer() << "min-outputs-value = " << cryptonote::print_money(m_wallet->get_min_output_value());
success_msg_writer() << "merge-destinations = " << m_wallet->merge_destinations();
success_msg_writer() << "confirm-backlog = " << m_wallet->confirm_backlog();
success_msg_writer() << "confirm-backlog-threshold = " << m_wallet->get_confirm_backlog_threshold();
success_msg_writer() << "confirm-export-overwrite = " << m_wallet->confirm_export_overwrite();
success_msg_writer() << "refresh-from-block-height = " << m_wallet->get_refresh_from_block_height();
success_msg_writer() << "auto-low-priority = " << m_wallet->auto_low_priority();
success_msg_writer() << "segregate-pre-fork-outputs = " << m_wallet->segregate_pre_fork_outputs();
success_msg_writer() << "key-reuse-mitigation2 = " << m_wallet->key_reuse_mitigation2();
const std::pair<size_t, size_t> lookahead = m_wallet->get_subaddress_lookahead();
@ -3310,17 +3204,14 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
CHECK_SIMPLE_VARIABLE("store-tx-info", set_store_tx_info, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("auto-refresh", set_auto_refresh, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("refresh-type", set_refresh_type, tr("full (slowest, no assumptions); optimize-coinbase (fast, assumes the whole coinbase is paid to a single address); no-coinbase (fastest, assumes we receive no coinbase transaction), default (same as optimize-coinbase)"));
CHECK_SIMPLE_VARIABLE("priority", set_default_priority, tr("0, 1, 2, 3, or 4, or one of ") << join_priority_strings(", "));
CHECK_SIMPLE_VARIABLE("priority", set_default_priority, tr("0-5 or one of ") << join_priority_strings(", "));
CHECK_SIMPLE_VARIABLE("ask-password", set_ask_password, tr("0|1|2 (or never|action|decrypt)"));
CHECK_SIMPLE_VARIABLE("unit", set_unit, tr("loki, megarok, kilorok, rok"));
CHECK_SIMPLE_VARIABLE("min-outputs-count", set_min_output_count, tr("unsigned integer"));
CHECK_SIMPLE_VARIABLE("min-outputs-value", set_min_output_value, tr("amount"));
CHECK_SIMPLE_VARIABLE("merge-destinations", set_merge_destinations, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("confirm-backlog", set_confirm_backlog, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("confirm-backlog-threshold", set_confirm_backlog_threshold, tr("unsigned integer"));
CHECK_SIMPLE_VARIABLE("confirm-export-overwrite", set_confirm_export_overwrite, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("refresh-from-block-height", set_refresh_from_block_height, tr("block height"));
CHECK_SIMPLE_VARIABLE("auto-low-priority", set_auto_low_priority, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("segregate-pre-fork-outputs", set_segregate_pre_fork_outputs, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("key-reuse-mitigation2", set_key_reuse_mitigation2, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("subaddress-lookahead", set_subaddress_lookahead, tr("<major>:<minor>"));
@ -5677,7 +5568,6 @@ static bool parse_subaddr_indices_and_priority(tools::wallet2 &wallet, std::vect
if (args.size() > 0 && tools::parse_priority(args[0], priority))
args.erase(args.begin());
priority = wallet.adjust_priority(priority);
return true;
}
//----------------------------------------------------------------------------------------------------
@ -5686,36 +5576,6 @@ bool simple_wallet::confirm_and_send_tx(std::vector<cryptonote::address_parse_in
if (ptx_vector.empty())
return false;
// if we need to check for backlog, check the worst case tx
if (m_wallet->confirm_backlog() && !blink)
{
std::stringstream prompt;
double worst_fee_per_byte = std::numeric_limits<double>::max();
for (size_t n = 0; n < ptx_vector.size(); ++n)
{
const uint64_t blob_size = cryptonote::tx_to_blob(ptx_vector[n].tx).size();
const double fee_per_byte = ptx_vector[n].fee / (double)blob_size;
if (fee_per_byte < worst_fee_per_byte)
{
worst_fee_per_byte = fee_per_byte;
}
}
std::string prompt_str = prompt.str();
if (!prompt_str.empty())
{
std::string accepted = input_line(prompt_str, true);
if (std::cin.eof())
return false;
if (!command_line::is_yes(accepted))
{
fail_msg_writer() << tr("transaction cancelled.");
return false;
}
}
}
// if more than one tx necessary, prompt user to confirm
if (m_wallet->always_confirm_transfers() || ptx_vector.size() > 1)
{
@ -7148,8 +7008,6 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
if (local_args.size() > 0 && tools::parse_priority(local_args[0], priority))
local_args.erase(local_args.begin());
priority = m_wallet->adjust_priority(priority);
size_t outputs = 1;
if (local_args.size() > 0 && local_args[0].substr(0, 8) == "outputs=")
{

View File

@ -140,7 +140,6 @@ namespace cryptonote
bool set_confirm_backlog_threshold(const std::vector<std::string> &args = std::vector<std::string>());
bool set_confirm_export_overwrite(const std::vector<std::string> &args = std::vector<std::string>());
bool set_refresh_from_block_height(const std::vector<std::string> &args = std::vector<std::string>());
bool set_auto_low_priority(const std::vector<std::string> &args = std::vector<std::string>());
bool set_segregate_pre_fork_outputs(const std::vector<std::string> &args = std::vector<std::string>());
bool set_key_reuse_mitigation2(const std::vector<std::string> &args = std::vector<std::string>());
bool set_subaddress_lookahead(const std::vector<std::string> &args = std::vector<std::string>());

View File

@ -1059,7 +1059,6 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
m_confirm_backlog(true),
m_confirm_backlog_threshold(0),
m_confirm_export_overwrite(true),
m_auto_low_priority(true),
m_segregate_pre_fork_outputs(true),
m_key_reuse_mitigation2(true),
m_segregation_height(0),
@ -3832,9 +3831,6 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
value2.SetInt(m_confirm_export_overwrite ? 1 :0);
json.AddMember("confirm_export_overwrite", value2, json.GetAllocator());
value2.SetInt(m_auto_low_priority ? 1 : 0);
json.AddMember("auto_low_priority", value2, json.GetAllocator());
value2.SetUint(m_nettype);
json.AddMember("nettype", value2, json.GetAllocator());
@ -3998,7 +3994,6 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_confirm_backlog = true;
m_confirm_backlog_threshold = 0;
m_confirm_export_overwrite = true;
m_auto_low_priority = true;
m_segregate_pre_fork_outputs = true;
m_key_reuse_mitigation2 = true;
m_segregation_height = 0;
@ -4137,8 +4132,6 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_confirm_backlog_threshold = field_confirm_backlog_threshold;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, confirm_export_overwrite, int, Int, false, true);
m_confirm_export_overwrite = field_confirm_export_overwrite;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, auto_low_priority, int, Int, false, true);
m_auto_low_priority = field_auto_low_priority;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, nettype, uint8_t, Uint, false, static_cast<uint8_t>(m_nettype));
// The network type given in the program argument is inconsistent with the network type saved in the wallet
THROW_WALLET_EXCEPTION_IF(static_cast<uint8_t>(m_nettype) != field_nettype, error::wallet_internal_error,
@ -7489,34 +7482,37 @@ bool wallet2::sign_multisig_tx_from_file(const std::string &filename, std::vecto
return sign_multisig_tx_to_file(exported_txs, filename, txids);
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2::get_fee_percent(uint32_t priority, int fee_algorithm) const
uint64_t wallet2::get_fee_percent(uint32_t priority, txtype type) const
{
static constexpr std::array<std::array<uint64_t, 4>, 3> percents = {{
{{100, 400, 2000, 16600}},
{{100, 500, 2500, 100000}},
{{100, 500, 2500, 12500}},
}};
static constexpr std::array<uint64_t, 4> percents{{100, 500, 2500, 12500}};
if (fee_algorithm == -1)
fee_algorithm = get_fee_algorithm();
const bool blinkable = type == txtype::standard;
// 0 -> default (here, x1 till fee algorithm 2, x4 from it)
if (priority == 0)
{
priority = m_default_priority;
if (priority == 0)
priority = fee_algorithm >= 1 ? 2 : 1;
if ((priority == tx_priority_blink && !blinkable) || priority == 0)
priority = tx_priority_unimportant;
}
// If it's a blinkable tx then we only have two relevant priorities: unimportant, and blink.
if (blinkable && priority != tx_priority_unimportant)
priority = tx_priority_blink;
if (priority == tx_priority_blink)
{
THROW_WALLET_EXCEPTION_IF(!use_fork_rules(HF_VERSION_BLINK, 0), error::invalid_priority);
return BLINK_MINER_TX_FEE_PERCENT + BLINK_BURN_TX_FEE_PERCENT;
uint64_t burn_pct;
if (use_fork_rules(network_version_15_lns, 0))
burn_pct = BLINK_BURN_TX_FEE_PERCENT;
else if (use_fork_rules(network_version_14_blink, 0))
burn_pct = BLINK_BURN_TX_FEE_PERCENT_OLD;
else
THROW_WALLET_EXCEPTION(error::invalid_priority);
return BLINK_MINER_TX_FEE_PERCENT + burn_pct;
}
THROW_WALLET_EXCEPTION_IF(
fee_algorithm < 0 || fee_algorithm >= (int)percents.size() ||
priority < 1 || priority > percents[0].size(),
error::invalid_priority);
return percents[fee_algorithm][priority-1];
THROW_WALLET_EXCEPTION_IF(priority > percents.size(), error::invalid_priority);
return percents[priority-1];
}
//----------------------------------------------------------------------------------------------------
byte_and_output_fees wallet2::get_dynamic_base_fee_estimate() const
@ -7556,98 +7552,6 @@ uint64_t wallet2::get_fee_quantization_mask() const
return 1;
return fee_quantization_mask;
}
//----------------------------------------------------------------------------------------------------
int wallet2::get_fee_algorithm() const
{
// changes at v13
if (use_fork_rules(HF_VERSION_PER_OUTPUT_FEE, 0))
return 2;
return 1; // last changed at v10
}
//----------------------------------------------------------------------------------------------------
uint32_t wallet2::adjust_priority(uint32_t priority)
{
constexpr uint32_t DEPRECATED_BLINK_PRIORITY = 0x626c6e6b; // "blnk"
if (priority == DEPRECATED_BLINK_PRIORITY)
{
priority = tx_priority_blink;
}
else if (priority == 0 && m_default_priority == 0 && auto_low_priority())
{
try
{
// check if there's a backlog in the tx pool
const uint64_t base_fee = get_base_fees().first;
const uint64_t fee_percent = get_fee_percent(1);
const double fee_level = base_fee * fee_percent / 100;
// NOTE (Loki): We don't include the per-output fee here because we typically don't actually
// know how many outputs we will need yet, but it's okay: fee_level being too low will just
// make us a little over-cautious about using low-priority but will still work fine when the
// pool is empty.
const std::vector<std::pair<uint64_t, uint64_t>> blocks = estimate_backlog({std::make_pair(fee_level, fee_level)});
if (blocks.size() != 1)
{
MERROR("Bad estimated backlog array size");
return priority;
}
else if (blocks[0].first > 0)
{
MINFO("We don't use the low priority because there's a backlog in the tx pool.");
return priority;
}
// get the current full reward zone
uint64_t block_weight_limit = 0;
const auto result = m_node_rpc_proxy.get_block_weight_limit(block_weight_limit);
throw_on_rpc_response_error(result, "get_info");
const uint64_t full_reward_zone = block_weight_limit / 2;
// get the last N block headers and sum the block sizes
const size_t N = 10;
if (m_blockchain.size() < N)
{
MERROR("The blockchain is too short");
return priority;
}
cryptonote::COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::request getbh_req{};
cryptonote::COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::response getbh_res{};
m_daemon_rpc_mutex.lock();
getbh_req.start_height = m_blockchain.size() - N;
getbh_req.end_height = m_blockchain.size() - 1;
bool r = invoke_http_json_rpc("/json_rpc", "getblockheadersrange", getbh_req, getbh_res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "getblockheadersrange");
THROW_WALLET_EXCEPTION_IF(getbh_res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "getblockheadersrange");
THROW_WALLET_EXCEPTION_IF(getbh_res.status != CORE_RPC_STATUS_OK, error::get_blocks_error, get_rpc_status(getbh_res.status));
if (getbh_res.headers.size() != N)
{
MERROR("Bad blockheaders size");
return priority;
}
size_t block_weight_sum = 0;
for (const cryptonote::block_header_response &i : getbh_res.headers)
{
block_weight_sum += i.block_weight;
}
// estimate how 'full' the last N blocks are
const size_t P = 100 * block_weight_sum / (N * full_reward_zone);
MINFO((boost::format("The last %d blocks fill roughly %d%% of the full reward zone.") % N % P).str());
if (P > 80)
{
MINFO("We don't use the low priority because recent blocks are quite full.");
return priority;
}
MINFO("We'll use the low priority because probably it's safe to do so.");
return 1;
}
catch (const std::exception &e)
{
MERROR(e.what());
}
}
return priority;
}
loki_construct_tx_params wallet2::construct_params(uint8_t hf_version, txtype tx_type, uint32_t priority, lns::burn_type lns_burn_type)
{
@ -7663,7 +7567,9 @@ loki_construct_tx_params wallet2::construct_params(uint8_t hf_version, txtype tx
else if (priority == tools::tx_priority_blink)
{
tx_params.burn_fixed = BLINK_BURN_FIXED;
tx_params.burn_percent = BLINK_BURN_TX_FEE_PERCENT;
tx_params.burn_percent = hf_version <= network_version_14_blink
? BLINK_BURN_TX_FEE_PERCENT_OLD
: BLINK_BURN_TX_FEE_PERCENT;
}
return tx_params;
@ -8120,8 +8026,6 @@ wallet2::stake_result wallet2::create_stake_tx(const crypto::public_key& service
try
{
priority = adjust_priority(priority);
if (priority == tx_priority_blink)
{
result.status = stake_result_status::no_blink;
@ -8189,8 +8093,6 @@ wallet2::register_service_node_result wallet2::create_register_service_node_tx(c
if (local_args.size() > 0 && parse_priority(local_args[0], priority))
local_args.erase(local_args.begin());
priority = adjust_priority(priority);
if (priority == tx_priority_blink)
{
result.status = register_service_node_result_status::no_blink;
@ -10330,7 +10232,6 @@ bool wallet2::light_wallet_key_image_is_ours(const crypto::key_image& key_image,
// time), and 5 bytes (max 34.3 LOKI) might conceivable not be enough.
static constexpr uint64_t BURN_FEE_PLACEHOLDER = (1ULL << (6*7)) - 1;
// Another implementation of transaction creation that is hopefully better
// While there is anything left to pay, it goes through random outputs and tries
// to fill the next destination/amount. If it fully fills it, it will use the
@ -10413,7 +10314,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
const rct::RCTConfig rct_config { rct::RangeProofPaddedBulletproof, 2 };
const auto base_fee = get_base_fees();
const uint64_t fee_percent = get_fee_percent(priority, get_fee_algorithm());
const uint64_t fee_percent = get_fee_percent(priority, tx_params.tx_type);
uint64_t fixed_fee = 0;
const uint64_t fee_quantization_mask = get_fee_quantization_mask();
@ -11073,7 +10974,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
const rct::RCTConfig rct_config { rct::RangeProofPaddedBulletproof, 2 };
const auto base_fee = get_base_fees();
const uint64_t fee_percent = get_fee_percent(priority, get_fee_algorithm());
const uint64_t fee_percent = get_fee_percent(priority, tx_type);
const uint64_t fee_quantization_mask = get_fee_quantization_mask();
uint64_t fixed_fee = 0;
@ -14170,77 +14071,6 @@ bool wallet2::is_synced() const
return get_blockchain_current_height() >= height;
}
//----------------------------------------------------------------------------------------------------
std::vector<std::pair<uint64_t, uint64_t>> wallet2::estimate_backlog(const std::vector<std::pair<double, double>> &fee_levels)
{
for (const auto &fee_level: fee_levels)
{
THROW_WALLET_EXCEPTION_IF(fee_level.first == 0.0, error::wallet_internal_error, "Invalid 0 fee");
THROW_WALLET_EXCEPTION_IF(fee_level.second == 0.0, error::wallet_internal_error, "Invalid 0 fee");
}
// get txpool backlog
cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG::request req{};
cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG::response res{};
m_daemon_rpc_mutex.lock();
bool r = invoke_http_json_rpc("/json_rpc", "get_txpool_backlog", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "Failed to connect to daemon");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_txpool_backlog");
THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::get_tx_pool_error);
uint64_t block_weight_limit = 0;
const auto result = m_node_rpc_proxy.get_block_weight_limit(block_weight_limit);
throw_on_rpc_response_error(result, "get_info");
uint64_t full_reward_zone = block_weight_limit / 2;
THROW_WALLET_EXCEPTION_IF(full_reward_zone == 0, error::wallet_internal_error, "Invalid block weight limit from daemon");
std::vector<std::pair<uint64_t, uint64_t>> blocks;
for (const auto &fee_level: fee_levels)
{
const double our_fee_byte_min = fee_level.first;
const double our_fee_byte_max = fee_level.second;
uint64_t priority_weight_min = 0, priority_weight_max = 0;
for (const auto &i: res.backlog)
{
if (i.weight == 0)
{
MWARNING("Got 0 weight tx from txpool, ignored");
continue;
}
double this_fee_byte = i.fee / (double)i.weight;
if (this_fee_byte >= our_fee_byte_min)
priority_weight_min += i.weight;
if (this_fee_byte >= our_fee_byte_max)
priority_weight_max += i.weight;
}
uint64_t nblocks_min = priority_weight_min / full_reward_zone;
uint64_t nblocks_max = priority_weight_max / full_reward_zone;
MDEBUG("estimate_backlog: priority_weight " << priority_weight_min << " - " << priority_weight_max << " for "
<< our_fee_byte_min << " - " << our_fee_byte_max << " rok byte fee, "
<< nblocks_min << " - " << nblocks_max << " blocks at block weight " << full_reward_zone);
blocks.push_back(std::make_pair(nblocks_min, nblocks_max));
}
return blocks;
}
//----------------------------------------------------------------------------------------------------
std::vector<std::pair<uint64_t, uint64_t>> wallet2::estimate_backlog(uint64_t min_tx_weight, uint64_t max_tx_weight, const std::vector<uint64_t> &fees)
{
THROW_WALLET_EXCEPTION_IF(min_tx_weight == 0, error::wallet_internal_error, "Invalid 0 fee");
THROW_WALLET_EXCEPTION_IF(max_tx_weight == 0, error::wallet_internal_error, "Invalid 0 fee");
for (uint64_t fee: fees)
{
THROW_WALLET_EXCEPTION_IF(fee == 0, error::wallet_internal_error, "Invalid 0 fee");
}
std::vector<std::pair<double, double>> fee_levels;
for (uint64_t fee: fees)
{
double our_fee_byte_min = fee / (double)min_tx_weight, our_fee_byte_max = fee / (double)max_tx_weight;
fee_levels.emplace_back(our_fee_byte_min, our_fee_byte_max);
}
return estimate_backlog(fee_levels);
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2::get_segregation_fork_height() const
{
if (m_nettype == TESTNET)
@ -14437,7 +14267,6 @@ uint64_t wallet2::hash_m_transfers(int64_t transfer_height, crypto::hash &hash)
return current_height;
}
constexpr std::array<const char* const, 5> allowed_priority_strings = {{"default", "unimportant", "normal", "elevated", "priority"}};
bool parse_subaddress_indices(const std::string& arg, std::set<uint32_t>& subaddr_indices, std::string *err_msg)
{
subaddr_indices.clear();
@ -14471,9 +14300,6 @@ bool parse_priority(const std::string& arg, uint32_t& priority)
if(priority_pos != allowed_priority_strings.end()) {
priority = std::distance(allowed_priority_strings.begin(), priority_pos);
return true;
} else if (arg == "blink") {
priority = tx_priority_blink;
return true;
}
return false;
}

View File

@ -1195,8 +1195,6 @@ private:
uint32_t get_confirm_backlog_threshold() const { return m_confirm_backlog_threshold; };
bool confirm_export_overwrite() const { return m_confirm_export_overwrite; }
void confirm_export_overwrite(bool always) { m_confirm_export_overwrite = always; }
bool auto_low_priority() const { return m_auto_low_priority; }
void auto_low_priority(bool value) { m_auto_low_priority = value; }
bool segregate_pre_fork_outputs() const { return m_segregate_pre_fork_outputs; }
void segregate_pre_fork_outputs(bool value) { m_segregate_pre_fork_outputs = value; }
bool key_reuse_mitigation2() const { return m_key_reuse_mitigation2; }
@ -1264,7 +1262,6 @@ private:
boost::optional<uint8_t> get_hard_fork_version() const { return m_node_rpc_proxy.get_hardfork_version(); }
bool use_fork_rules(uint8_t version, uint64_t early_blocks = 0) const;
int get_fee_algorithm() const;
std::string get_wallet_file() const;
std::string get_keys_file() const;
@ -1383,13 +1380,9 @@ private:
bool is_synced() const;
std::vector<std::pair<uint64_t, uint64_t>> estimate_backlog(const std::vector<std::pair<double, double>> &fee_levels);
std::vector<std::pair<uint64_t, uint64_t>> estimate_backlog(uint64_t min_tx_weight, uint64_t max_tx_weight, const std::vector<uint64_t> &fees);
uint64_t get_fee_percent(uint32_t priority, int fee_algorithm = -1) const;
uint64_t get_fee_percent(uint32_t priority, cryptonote::txtype type) const;
cryptonote::byte_and_output_fees get_base_fees() const;
uint64_t get_fee_quantization_mask() const;
uint32_t adjust_priority(uint32_t priority);
// params constructor, accumulates the burn amounts if the priority is
// a blink and, or a lns tx. If it is a blink TX, lns_burn_type is ignored.
@ -1751,7 +1744,6 @@ private:
bool m_confirm_backlog;
uint32_t m_confirm_backlog_threshold;
bool m_confirm_export_overwrite;
bool m_auto_low_priority;
bool m_segregate_pre_fork_outputs;
bool m_key_reuse_mitigation2;
uint64_t m_segregation_height;
@ -1816,7 +1808,7 @@ private:
// TODO(loki): The better question is if anyone is ever going to try use
// register service node funded by multiple subaddresses. This is unlikely.
extern const std::array<const char* const, 5> allowed_priority_strings;
constexpr std::array<const char* const, 6> allowed_priority_strings = {{"default", "unimportant", "normal", "elevated", "priority", "blink"}};
bool parse_subaddress_indices(const std::string& arg, std::set<uint32_t>& subaddr_indices, std::string *err_msg = nullptr);
bool parse_priority (const std::string& arg, uint32_t& priority);

View File

@ -860,8 +860,10 @@ namespace tools
try
{
uint32_t priority = m_wallet->adjust_priority(req.priority);
if (req.blink) priority = tools::tx_priority_blink;
uint32_t priority = req.priority;
if (req.blink || priority == 0x626c6e6b /* deprecated blink priority, can remove post-HF15 */)
priority = tx_priority_blink;
boost::optional<uint8_t> hf_version = m_wallet->get_hard_fork_version();
if (!hf_version)
@ -921,8 +923,10 @@ namespace tools
try
{
uint32_t priority = m_wallet->adjust_priority(req.priority);
if (req.blink) priority = tools::tx_priority_blink;
uint32_t priority = req.priority;
if (req.blink || priority == 0x626c6e6b /* deprecated blink priority, can remove post-HF15 */)
priority = tx_priority_blink;
boost::optional<uint8_t> hf_version = m_wallet->get_hard_fork_version();
if (!hf_version)
@ -1341,8 +1345,11 @@ namespace tools
try
{
uint32_t priority = m_wallet->adjust_priority(req.priority);
if (req.blink) priority = tools::tx_priority_blink;
uint32_t priority = req.priority;
if (req.blink || priority == 0x626c6e6b /* deprecated blink priority, can remove post-HF15 */)
priority = tx_priority_blink;
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_all(req.below_amount, dsts[0].addr, dsts[0].is_subaddress, req.outputs, CRYPTONOTE_DEFAULT_TX_MIXIN, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices);
return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.multisig_txset, res.unsigned_txset, req.do_not_relay, priority == tx_priority_blink,
@ -1396,9 +1403,11 @@ namespace tools
try
{
uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0);
uint32_t priority = m_wallet->adjust_priority(req.priority);
if (req.blink) priority = tools::tx_priority_blink;
uint32_t priority = req.priority;
if (req.blink || priority == 0x626c6e6b /* deprecated blink priority, can remove post-HF15 */)
priority = tx_priority_blink;
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_single(ki, dsts[0].addr, dsts[0].is_subaddress, req.outputs, CRYPTONOTE_DEFAULT_TX_MIXIN, req.unlock_time, priority, extra);
if (ptx_vector.empty())

View File

@ -482,7 +482,7 @@ namespace wallet_rpc
std::list<transfer_destination> destinations; // Array of destinations to receive LOKI.
uint32_t account_index; // (Optional) Transfer from this account index. (Defaults to 0)
std::set<uint32_t> subaddr_indices; // (Optional) Transfer from this set of subaddresses. (Defaults to 0)
uint32_t priority; // Set a priority for the transaction. Accepted values are: or 0-5 for: default, unimportant, normal, elevated, priority, blink.
uint32_t priority; // Set a priority for the transaction. Accepted values are: 1 for unimportant or 5 for blink. (0 and 2-4 are accepted for backwards compatibility and are equivalent to 5)
bool blink; // (Deprecated) Set priority to 5 for blink, field is deprecated: specifies that the tx should be blinked (`priority` will be ignored).
uint64_t ring_size; // (Deprecated) Ignored; Loki ring_size is statically set to 10.
uint64_t unlock_time; // Number of blocks before the loki can be spent (0 to use the default lock time).
@ -543,7 +543,7 @@ namespace wallet_rpc
std::list<transfer_destination> destinations; // Array of destinations to receive LOKI:
uint32_t account_index; // (Optional) Transfer from this account index. (Defaults to 0)
std::set<uint32_t> subaddr_indices; // (Optional) Transfer from this set of subaddresses. (Defaults to 0)
uint32_t priority; // Set a priority for the transaction. Accepted values are: or 0-5 for: default, unimportant, normal, elevated, priority, blink.
uint32_t priority; // Set a priority for the transaction. Accepted values are: 1 for unimportant or 5 for blink. (0 and 2-4 are accepted for backwards compatibility and are equivalent to 5)
bool blink; // (Deprecated) Set priority to 5 for blink, field is deprecated: specifies that the tx should be blinked (`priority` will be ignored).
uint64_t ring_size; // (Deprecated) Ignored. Loki ring_size is statically set to 10.
uint64_t unlock_time; // Number of blocks before the loki can be spent (0 to not add a lock).
@ -793,7 +793,7 @@ namespace wallet_rpc
std::string address; // Destination public address.
uint32_t account_index; // Sweep transactions from this account.
std::set<uint32_t> subaddr_indices; // (Optional) Sweep from this set of subaddresses in the account.
uint32_t priority; // Set a priority for the transaction. Accepted values are: or 0-5 for: default, unimportant, normal, elevated, priority, blink.
uint32_t priority; // Set a priority for the transaction. Accepted values are: 1 for unimportant or 5 for blink. (0 and 2-4 are accepted for backwards compatibility and are equivalent to 5)
bool blink; // (Deprecated) Set priority to 5 for blink, field is deprecated: specifies that the tx should be blinked (`priority` will be ignored).
uint64_t ring_size; // (Deprecated) Ignored; Loki ring_size is statically set to 10.
uint64_t outputs; //
@ -865,7 +865,7 @@ namespace wallet_rpc
struct request_t
{
std::string address; // Destination public address.
uint32_t priority; // Set a priority for the transaction. Accepted values are: or 0-5 for: default, unimportant, normal, elevated, priority, blink.
uint32_t priority; // Set a priority for the transaction. Accepted values are: 1 for unimportant or 5 for blink. (0 and 2-4 are accepted for backwards compatibility and are equivalent to 5)
bool blink; // (Deprecated) Set priority to 5 for blink, field is deprecated: specifies that the tx should be blinked (`priority` will be ignored).
uint64_t ring_size; // (Deprecated) Ignored; Loki ring_size is statically set to 10.
uint64_t outputs; //