mirror of
https://github.com/monero-project/monero.git
synced 2024-12-24 20:49:37 +00:00
wallet: add a fee multiplier
Fee can now be multiplied by 2 or 3, if users want to give priority to their transactions. There are only three levels to avoid too much fingerprinting. Default is 1 (minimum fee). The default multiplier can be set by "set fee-multiplier X".
This commit is contained in:
parent
de91bb75a1
commit
945c272f6c
7 changed files with 146 additions and 28 deletions
|
@ -485,6 +485,68 @@ bool simple_wallet::set_default_mixin(const std::vector<std::string> &args/* = s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool simple_wallet::set_default_fee_multiplier(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
|
||||||
|
{
|
||||||
|
bool success = false;
|
||||||
|
int fee_multiplier = 0;
|
||||||
|
if (m_wallet->watch_only())
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("wallet is watch-only and cannot transfer");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (strchr(args[1].c_str(), '-'))
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("fee multiplier must be 0, 1, 2, or 3 ");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (args[1] == "0")
|
||||||
|
{
|
||||||
|
fee_multiplier = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fee_multiplier = boost::lexical_cast<int>(args[1]);
|
||||||
|
if (fee_multiplier != 1 && fee_multiplier != 2 && fee_multiplier != 3)
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("fee multiplier must be 0, 1, 2, or 3");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tools::password_container pwd_container;
|
||||||
|
success = pwd_container.read_password();
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("failed to read wallet password");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify password before using so user doesn't accidentally set a new password for rewritten wallet */
|
||||||
|
success = m_wallet->verify_password(pwd_container.password());
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("invalid password");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_wallet->set_default_fee_multiplier(fee_multiplier);
|
||||||
|
m_wallet->rewrite(m_wallet_file, pwd_container.password());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch(const boost::bad_lexical_cast &)
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("fee multiplier must be 0, 1, 2 or 3");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("could not change default fee multiplier");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool simple_wallet::set_auto_refresh(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
|
bool simple_wallet::set_auto_refresh(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
|
||||||
{
|
{
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
@ -587,7 +649,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; 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 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"));
|
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; 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 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; fee-multiplier [1|2|3] - normal/elevated/priority fee"));
|
||||||
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>"));
|
||||||
|
@ -609,6 +671,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
|
||||||
success_msg_writer() << "default-mixin = " << m_wallet->default_mixin();
|
success_msg_writer() << "default-mixin = " << m_wallet->default_mixin();
|
||||||
success_msg_writer() << "auto-refresh = " << m_wallet->auto_refresh();
|
success_msg_writer() << "auto-refresh = " << m_wallet->auto_refresh();
|
||||||
success_msg_writer() << "refresh-type = " << get_refresh_type_name(m_wallet->get_refresh_type());
|
success_msg_writer() << "refresh-type = " << get_refresh_type_name(m_wallet->get_refresh_type());
|
||||||
|
success_msg_writer() << "fee-multiplier = " << m_wallet->get_default_fee_multiplier();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -704,6 +767,21 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (args[0] == "fee-multiplier")
|
||||||
|
{
|
||||||
|
if (args.size() <= 1)
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("set fee-multiplier: needs an argument: 0, 1, 2, or 3");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::vector<std::string> local_args = args;
|
||||||
|
local_args.erase(local_args.begin(), local_args.begin()+2);
|
||||||
|
set_default_fee_multiplier(local_args);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fail_msg_writer() << tr("set: unrecognized argument(s)");
|
fail_msg_writer() << tr("set: unrecognized argument(s)");
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -142,6 +142,7 @@ namespace cryptonote
|
||||||
bool set_tx_note(const std::vector<std::string> &args);
|
bool set_tx_note(const std::vector<std::string> &args);
|
||||||
bool get_tx_note(const std::vector<std::string> &args);
|
bool get_tx_note(const std::vector<std::string> &args);
|
||||||
bool status(const std::vector<std::string> &args);
|
bool status(const std::vector<std::string> &args);
|
||||||
|
bool set_default_fee_multiplier(const std::vector<std::string> &args);
|
||||||
|
|
||||||
uint64_t get_daemon_blockchain_height(std::string& err);
|
uint64_t get_daemon_blockchain_height(std::string& err);
|
||||||
bool try_connect_to_daemon();
|
bool try_connect_to_daemon();
|
||||||
|
|
|
@ -94,11 +94,12 @@ void do_prepare_file_names(const std::string& file_path, std::string& keys_file,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t calculate_fee(const cryptonote::blobdata &blob)
|
uint64_t calculate_fee(const cryptonote::blobdata &blob, uint64_t fee_multiplier)
|
||||||
{
|
{
|
||||||
|
THROW_WALLET_EXCEPTION_IF(fee_multiplier <= 0 || fee_multiplier > 3, tools::error::invalid_fee_multiplier);
|
||||||
uint64_t bytes = blob.size();
|
uint64_t bytes = blob.size();
|
||||||
uint64_t kB = (bytes + 1023) / 1024;
|
uint64_t kB = (bytes + 1023) / 1024;
|
||||||
return kB * FEE_PER_KB;
|
return kB * FEE_PER_KB * fee_multiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
} //namespace
|
} //namespace
|
||||||
|
@ -1054,6 +1055,9 @@ bool wallet2::store_keys(const std::string& keys_file_name, const std::string& p
|
||||||
value2.SetUint(m_default_mixin);
|
value2.SetUint(m_default_mixin);
|
||||||
json.AddMember("default_mixin", value2, json.GetAllocator());
|
json.AddMember("default_mixin", value2, json.GetAllocator());
|
||||||
|
|
||||||
|
value2.SetUint(m_default_fee_multiplier);
|
||||||
|
json.AddMember("default_fee_multiplier", value2, json.GetAllocator());
|
||||||
|
|
||||||
value2.SetInt(m_auto_refresh ? 1 :0);
|
value2.SetInt(m_auto_refresh ? 1 :0);
|
||||||
json.AddMember("auto_refresh", value2, json.GetAllocator());
|
json.AddMember("auto_refresh", value2, json.GetAllocator());
|
||||||
|
|
||||||
|
@ -1125,6 +1129,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const std::string& pa
|
||||||
m_watch_only = false;
|
m_watch_only = false;
|
||||||
m_always_confirm_transfers = false;
|
m_always_confirm_transfers = false;
|
||||||
m_default_mixin = 0;
|
m_default_mixin = 0;
|
||||||
|
m_default_fee_multiplier = 0;
|
||||||
m_auto_refresh = true;
|
m_auto_refresh = true;
|
||||||
m_refresh_type = RefreshType::RefreshDefault;
|
m_refresh_type = RefreshType::RefreshDefault;
|
||||||
}
|
}
|
||||||
|
@ -1158,6 +1163,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const std::string& pa
|
||||||
|| (field_store_tx_info_found && (field_store_tx_info != 0));
|
|| (field_store_tx_info_found && (field_store_tx_info != 0));
|
||||||
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, default_mixin, unsigned int, Uint, false);
|
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, default_mixin, unsigned int, Uint, false);
|
||||||
m_default_mixin = field_default_mixin_found ? field_default_mixin : 0;
|
m_default_mixin = field_default_mixin_found ? field_default_mixin : 0;
|
||||||
|
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, default_fee_multiplier, unsigned int, Uint, false);
|
||||||
|
m_default_fee_multiplier = field_default_fee_multiplier_found ? field_default_fee_multiplier : 0;
|
||||||
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, auto_refresh, int, Int, false);
|
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, auto_refresh, int, Int, false);
|
||||||
m_auto_refresh = !field_auto_refresh_found || (field_auto_refresh != 0);
|
m_auto_refresh = !field_auto_refresh_found || (field_auto_refresh != 0);
|
||||||
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, refresh_type, int, Int, false);
|
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, refresh_type, int, Int, false);
|
||||||
|
@ -2081,15 +2088,29 @@ void wallet2::commit_tx(std::vector<pending_tx>& ptx_vector)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t wallet2::sanitize_fee_multiplier(uint64_t fee_multiplier) const
|
||||||
|
{
|
||||||
|
// 0, default value used for previous fee argument, defaults to normal fee
|
||||||
|
if (fee_multiplier == 0)
|
||||||
|
return m_default_fee_multiplier > 0 ? m_default_fee_multiplier : 1;
|
||||||
|
// 1 to 3 are allowed as multipliers
|
||||||
|
if (fee_multiplier >= 1 && fee_multiplier <= 3)
|
||||||
|
return fee_multiplier;
|
||||||
|
THROW_WALLET_EXCEPTION_IF (false, error::invalid_fee_multiplier);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
// 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
|
||||||
// transactions will be required
|
// transactions will be required
|
||||||
std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector<uint8_t> extra, bool trusted_daemon)
|
std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint64_t fee_multiplier, const std::vector<uint8_t> extra, bool trusted_daemon)
|
||||||
{
|
{
|
||||||
const std::vector<size_t> unused_transfers_indices = select_available_outputs_from_histogram(fake_outs_count + 1, true, trusted_daemon);
|
const std::vector<size_t> unused_transfers_indices = select_available_outputs_from_histogram(fake_outs_count + 1, true, trusted_daemon);
|
||||||
|
|
||||||
|
fee_multiplier = sanitize_fee_multiplier(fee_multiplier);
|
||||||
|
|
||||||
// failsafe split attempt counter
|
// failsafe split attempt counter
|
||||||
size_t attempt_count = 0;
|
size_t attempt_count = 0;
|
||||||
|
|
||||||
|
@ -2120,7 +2141,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<crypto
|
||||||
{
|
{
|
||||||
transfer(dst_vector, fake_outs_count, unused_transfers_indices, unlock_time, needed_fee, extra, tx, ptx, trusted_daemon);
|
transfer(dst_vector, fake_outs_count, unused_transfers_indices, unlock_time, needed_fee, extra, tx, ptx, trusted_daemon);
|
||||||
auto txBlob = t_serializable_object_to_blob(ptx.tx);
|
auto txBlob = t_serializable_object_to_blob(ptx.tx);
|
||||||
needed_fee = calculate_fee(txBlob);
|
needed_fee = calculate_fee(txBlob, fee_multiplier);
|
||||||
} while (ptx.fee < needed_fee);
|
} while (ptx.fee < needed_fee);
|
||||||
|
|
||||||
ptx_vector.push_back(ptx);
|
ptx_vector.push_back(ptx);
|
||||||
|
@ -2358,7 +2379,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
|
||||||
// This system allows for sending (almost) the entire balance, since it does
|
// This system allows for sending (almost) the entire balance, since it does
|
||||||
// not generate spurious change in all txes, thus decreasing the instantaneous
|
// not generate spurious change in all txes, thus decreasing the instantaneous
|
||||||
// usable balance.
|
// usable balance.
|
||||||
std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector<uint8_t> extra, bool trusted_daemon)
|
std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint64_t fee_multiplier, const std::vector<uint8_t> extra, bool trusted_daemon)
|
||||||
{
|
{
|
||||||
std::vector<size_t> unused_transfers_indices;
|
std::vector<size_t> unused_transfers_indices;
|
||||||
std::vector<size_t> unused_dust_indices;
|
std::vector<size_t> unused_dust_indices;
|
||||||
|
@ -2388,6 +2409,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||||
// 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);
|
||||||
|
|
||||||
|
fee_multiplier = sanitize_fee_multiplier (fee_multiplier);
|
||||||
|
|
||||||
// calculate total amount being sent to all destinations
|
// calculate total amount being sent to all destinations
|
||||||
// throw if total amount overflows uint64_t
|
// throw if total amount overflows uint64_t
|
||||||
needed_money = 0;
|
needed_money = 0;
|
||||||
|
@ -2499,7 +2522,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||||
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, unlock_time, needed_fee, extra,
|
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, unlock_time, needed_fee, extra,
|
||||||
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
|
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
|
||||||
auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
|
auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
|
||||||
needed_fee = calculate_fee(txBlob);
|
needed_fee = calculate_fee(txBlob, fee_multiplier);
|
||||||
available_for_fee = test_ptx.fee + test_ptx.change_dts.amount + (!test_ptx.dust_added_to_fee ? test_ptx.dust : 0);
|
available_for_fee = test_ptx.fee + test_ptx.change_dts.amount + (!test_ptx.dust_added_to_fee ? test_ptx.dust : 0);
|
||||||
LOG_PRINT_L2("Made a " << txBlob.size() << " kB tx, with " << print_money(available_for_fee) << " available for fee (" <<
|
LOG_PRINT_L2("Made a " << txBlob.size() << " kB tx, with " << print_money(available_for_fee) << " available for fee (" <<
|
||||||
print_money(needed_fee) << " needed)");
|
print_money(needed_fee) << " needed)");
|
||||||
|
@ -2582,7 +2605,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||||
return ptx_vector;
|
return ptx_vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<wallet2::pending_tx> wallet2::create_transactions_all(const cryptonote::account_public_address &address, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector<uint8_t> extra, bool trusted_daemon)
|
std::vector<wallet2::pending_tx> wallet2::create_transactions_all(const cryptonote::account_public_address &address, const size_t fake_outs_count, const uint64_t unlock_time, uint64_t fee_multiplier, const std::vector<uint8_t> extra, bool trusted_daemon)
|
||||||
{
|
{
|
||||||
std::vector<size_t> unused_transfers_indices;
|
std::vector<size_t> unused_transfers_indices;
|
||||||
std::vector<size_t> unused_dust_indices;
|
std::vector<size_t> unused_dust_indices;
|
||||||
|
@ -2598,6 +2621,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(const cryptono
|
||||||
uint64_t needed_fee, available_for_fee = 0;
|
uint64_t needed_fee, available_for_fee = 0;
|
||||||
uint64_t upper_transaction_size_limit = get_upper_tranaction_size_limit();
|
uint64_t upper_transaction_size_limit = get_upper_tranaction_size_limit();
|
||||||
|
|
||||||
|
fee_multiplier = sanitize_fee_multiplier(fee_multiplier);
|
||||||
|
|
||||||
// gather all our dust and non dust outputs
|
// gather all our dust and non dust outputs
|
||||||
for (size_t i = 0; i < m_transfers.size(); ++i)
|
for (size_t i = 0; i < m_transfers.size(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -2626,7 +2651,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(const cryptono
|
||||||
// get a random unspent output and use it to pay next chunk. We try to alternate
|
// get a random unspent output and use it to pay next chunk. We try to alternate
|
||||||
// dust and non dust to ensure we never get with only dust, from which we might
|
// dust and non dust to ensure we never get with only dust, from which we might
|
||||||
// get a tx that can't pay for itself
|
// get a tx that can't pay for itself
|
||||||
size_t idx = unused_transfers_indices.empty() ? pop_random_value(unused_dust_indices) : unused_dust_indices.empty() ? pop_random_value(unused_transfers_indices) : ((tx.selected_transfers.size() & 1) || accumulated_outputs > FEE_PER_KB * (upper_transaction_size_limit + 1023) / 1024) ? pop_random_value(unused_dust_indices) : pop_random_value(unused_transfers_indices);
|
size_t idx = unused_transfers_indices.empty() ? pop_random_value(unused_dust_indices) : unused_dust_indices.empty() ? pop_random_value(unused_transfers_indices) : ((tx.selected_transfers.size() & 1) || accumulated_outputs > FEE_PER_KB * fee_multiplier * (upper_transaction_size_limit + 1023) / 1024) ? pop_random_value(unused_dust_indices) : pop_random_value(unused_transfers_indices);
|
||||||
|
|
||||||
const transfer_details &td = m_transfers[idx];
|
const transfer_details &td = m_transfers[idx];
|
||||||
LOG_PRINT_L2("Picking output " << idx << ", amount " << print_money(td.amount()));
|
LOG_PRINT_L2("Picking output " << idx << ", amount " << print_money(td.amount()));
|
||||||
|
@ -2654,7 +2679,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(const cryptono
|
||||||
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, unlock_time, needed_fee, extra,
|
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, unlock_time, needed_fee, extra,
|
||||||
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
|
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
|
||||||
auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
|
auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
|
||||||
needed_fee = calculate_fee(txBlob);
|
needed_fee = calculate_fee(txBlob, fee_multiplier);
|
||||||
available_for_fee = test_ptx.fee + test_ptx.dests[0].amount + test_ptx.change_dts.amount;
|
available_for_fee = test_ptx.fee + test_ptx.dests[0].amount + test_ptx.change_dts.amount;
|
||||||
LOG_PRINT_L2("Made a " << txBlob.size() << " kB tx, with " << print_money(available_for_fee) << " available for fee (" <<
|
LOG_PRINT_L2("Made a " << txBlob.size() << " kB tx, with " << print_money(available_for_fee) << " available for fee (" <<
|
||||||
print_money(needed_fee) << " needed)");
|
print_money(needed_fee) << " needed)");
|
||||||
|
@ -2667,7 +2692,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(const cryptono
|
||||||
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, unlock_time, needed_fee, extra,
|
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, unlock_time, needed_fee, extra,
|
||||||
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
|
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
|
||||||
txBlob = t_serializable_object_to_blob(test_ptx.tx);
|
txBlob = t_serializable_object_to_blob(test_ptx.tx);
|
||||||
needed_fee = calculate_fee(txBlob);
|
needed_fee = calculate_fee(txBlob, fee_multiplier);
|
||||||
LOG_PRINT_L2("Made an attempt at a final " << ((txBlob.size() + 1023)/1024) << " kB tx, with " << print_money(test_ptx.fee) <<
|
LOG_PRINT_L2("Made an attempt at a final " << ((txBlob.size() + 1023)/1024) << " kB tx, with " << print_money(test_ptx.fee) <<
|
||||||
" fee and " << print_money(test_ptx.change_dts.amount) << " change");
|
" fee and " << print_money(test_ptx.change_dts.amount) << " change");
|
||||||
} while (needed_fee > test_ptx.fee);
|
} while (needed_fee > test_ptx.fee);
|
||||||
|
@ -2994,13 +3019,13 @@ std::vector<wallet2::pending_tx> wallet2::create_unmixable_sweep_transactions(bo
|
||||||
{
|
{
|
||||||
transfer_from(unmixable_outputs, num_outputs_per_tx, (uint64_t)0 /* unlock_time */, 0, detail::digit_split_strategy, dust_policy, extra, tx, ptx);
|
transfer_from(unmixable_outputs, num_outputs_per_tx, (uint64_t)0 /* unlock_time */, 0, detail::digit_split_strategy, dust_policy, extra, tx, ptx);
|
||||||
auto txBlob = t_serializable_object_to_blob(ptx.tx);
|
auto txBlob = t_serializable_object_to_blob(ptx.tx);
|
||||||
needed_fee = calculate_fee(txBlob);
|
needed_fee = calculate_fee(txBlob, 1);
|
||||||
|
|
||||||
// reroll the tx with the actual amount minus the fee
|
// reroll the tx with the actual amount minus the fee
|
||||||
// if there's not enough for the fee, it'll throw
|
// if there's not enough for the fee, it'll throw
|
||||||
transfer_from(unmixable_outputs, num_outputs_per_tx, (uint64_t)0 /* unlock_time */, needed_fee, detail::digit_split_strategy, dust_policy, extra, tx, ptx);
|
transfer_from(unmixable_outputs, num_outputs_per_tx, (uint64_t)0 /* unlock_time */, needed_fee, detail::digit_split_strategy, dust_policy, extra, tx, ptx);
|
||||||
txBlob = t_serializable_object_to_blob(ptx.tx);
|
txBlob = t_serializable_object_to_blob(ptx.tx);
|
||||||
needed_fee = calculate_fee(txBlob);
|
needed_fee = calculate_fee(txBlob, 1);
|
||||||
} while (ptx.fee < needed_fee);
|
} while (ptx.fee < needed_fee);
|
||||||
|
|
||||||
ptx_vector.push_back(ptx);
|
ptx_vector.push_back(ptx);
|
||||||
|
|
|
@ -88,10 +88,10 @@ namespace tools
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wallet2(const wallet2&) : m_run(true), m_callback(0), m_testnet(false), m_always_confirm_transfers (false), m_store_tx_info(true), m_default_mixin(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0) {}
|
wallet2(const wallet2&) : m_run(true), m_callback(0), m_testnet(false), m_always_confirm_transfers (false), m_store_tx_info(true), m_default_mixin(0), m_default_fee_multiplier(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
wallet2(bool testnet = false, bool restricted = false) : m_run(true), m_callback(0), m_testnet(testnet), m_restricted(restricted), is_old_file_format(false), m_store_tx_info(true), m_default_mixin(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0) {}
|
wallet2(bool testnet = false, bool restricted = false) : m_run(true), m_callback(0), m_testnet(testnet), m_restricted(restricted), is_old_file_format(false), m_store_tx_info(true), m_default_mixin(0), m_default_fee_multiplier(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0) {}
|
||||||
struct transfer_details
|
struct transfer_details
|
||||||
{
|
{
|
||||||
uint64_t m_block_height;
|
uint64_t m_block_height;
|
||||||
|
@ -291,9 +291,9 @@ namespace tools
|
||||||
|
|
||||||
void commit_tx(pending_tx& ptx_vector);
|
void commit_tx(pending_tx& ptx_vector);
|
||||||
void commit_tx(std::vector<pending_tx>& ptx_vector);
|
void commit_tx(std::vector<pending_tx>& ptx_vector);
|
||||||
std::vector<pending_tx> create_transactions(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee, const std::vector<uint8_t> extra, bool trusted_daemon);
|
std::vector<pending_tx> create_transactions(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint64_t fee_multiplier, const std::vector<uint8_t> extra, bool trusted_daemon);
|
||||||
std::vector<wallet2::pending_tx> create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector<uint8_t> extra, bool trusted_daemon);
|
std::vector<wallet2::pending_tx> create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint64_t fee_multiplier, const std::vector<uint8_t> extra, bool trusted_daemon);
|
||||||
std::vector<wallet2::pending_tx> create_transactions_all(const cryptonote::account_public_address &address, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector<uint8_t> extra, bool trusted_daemon);
|
std::vector<wallet2::pending_tx> create_transactions_all(const cryptonote::account_public_address &address, const size_t fake_outs_count, const uint64_t unlock_time, uint64_t fee_multiplier, const std::vector<uint8_t> extra, bool trusted_daemon);
|
||||||
std::vector<pending_tx> create_unmixable_sweep_transactions(bool trusted_daemon);
|
std::vector<pending_tx> create_unmixable_sweep_transactions(bool trusted_daemon);
|
||||||
bool check_connection();
|
bool check_connection();
|
||||||
void get_transfers(wallet2::transfer_container& incoming_transfers) const;
|
void get_transfers(wallet2::transfer_container& incoming_transfers) const;
|
||||||
|
@ -363,6 +363,8 @@ namespace tools
|
||||||
void store_tx_info(bool store) { m_store_tx_info = store; }
|
void store_tx_info(bool store) { m_store_tx_info = store; }
|
||||||
uint32_t default_mixin() const { return m_default_mixin; }
|
uint32_t default_mixin() const { return m_default_mixin; }
|
||||||
void default_mixin(uint32_t m) { m_default_mixin = m; }
|
void default_mixin(uint32_t m) { m_default_mixin = m; }
|
||||||
|
uint32_t get_default_fee_multiplier() const { return m_default_fee_multiplier; }
|
||||||
|
void set_default_fee_multiplier(uint32_t m) { m_default_fee_multiplier = m; }
|
||||||
bool auto_refresh() const { return m_auto_refresh; }
|
bool auto_refresh() const { return m_auto_refresh; }
|
||||||
void auto_refresh(bool r) { m_auto_refresh = r; }
|
void auto_refresh(bool r) { m_auto_refresh = r; }
|
||||||
|
|
||||||
|
@ -423,6 +425,7 @@ namespace tools
|
||||||
uint64_t get_upper_tranaction_size_limit();
|
uint64_t get_upper_tranaction_size_limit();
|
||||||
void check_pending_txes();
|
void check_pending_txes();
|
||||||
std::vector<uint64_t> get_unspent_amounts_vector();
|
std::vector<uint64_t> get_unspent_amounts_vector();
|
||||||
|
uint64_t sanitize_fee_multiplier(uint64_t fee_multiplier) const;
|
||||||
|
|
||||||
cryptonote::account_base m_account;
|
cryptonote::account_base m_account;
|
||||||
std::string m_daemon_address;
|
std::string m_daemon_address;
|
||||||
|
@ -455,6 +458,7 @@ namespace tools
|
||||||
bool m_always_confirm_transfers;
|
bool m_always_confirm_transfers;
|
||||||
bool m_store_tx_info; /*!< request txkey to be returned in RPC, and store in the wallet cache file */
|
bool m_store_tx_info; /*!< request txkey to be returned in RPC, and store in the wallet cache file */
|
||||||
uint32_t m_default_mixin;
|
uint32_t m_default_mixin;
|
||||||
|
uint32_t m_default_fee_multiplier;
|
||||||
RefreshType m_refresh_type;
|
RefreshType m_refresh_type;
|
||||||
bool m_auto_refresh;
|
bool m_auto_refresh;
|
||||||
uint64_t m_refresh_from_block_height;
|
uint64_t m_refresh_from_block_height;
|
||||||
|
|
|
@ -56,6 +56,7 @@ namespace tools
|
||||||
// file_read_error
|
// file_read_error
|
||||||
// file_save_error
|
// file_save_error
|
||||||
// invalid_password
|
// invalid_password
|
||||||
|
// invalid_fee_multiplier
|
||||||
// refresh_error *
|
// refresh_error *
|
||||||
// acc_outs_lookup_error
|
// acc_outs_lookup_error
|
||||||
// block_parse_error
|
// block_parse_error
|
||||||
|
@ -226,6 +227,15 @@ namespace tools
|
||||||
|
|
||||||
std::string to_string() const { return wallet_logic_error::to_string(); }
|
std::string to_string() const { return wallet_logic_error::to_string(); }
|
||||||
};
|
};
|
||||||
|
struct invalid_fee_multiplier : public wallet_logic_error
|
||||||
|
{
|
||||||
|
explicit invalid_fee_multiplier(std::string&& loc)
|
||||||
|
: wallet_logic_error(std::move(loc), "invalid fee multiplier")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string() const { return wallet_logic_error::to_string(); }
|
||||||
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
struct invalid_pregenerated_random : public wallet_logic_error
|
struct invalid_pregenerated_random : public wallet_logic_error
|
||||||
|
|
|
@ -232,7 +232,7 @@ namespace tools
|
||||||
LOG_PRINT_L1("Requested mixin " << req.mixin << " too low for hard fork 2, using 2");
|
LOG_PRINT_L1("Requested mixin " << req.mixin << " too low for hard fork 2, using 2");
|
||||||
mixin = 2;
|
mixin = 2;
|
||||||
}
|
}
|
||||||
std::vector<wallet2::pending_tx> ptx_vector = m_wallet.create_transactions(dsts, mixin, req.unlock_time, req.fee, extra, req.trusted_daemon);
|
std::vector<wallet2::pending_tx> ptx_vector = m_wallet.create_transactions(dsts, mixin, req.unlock_time, req.fee_multiplier, extra, req.trusted_daemon);
|
||||||
|
|
||||||
// reject proposed transactions if there are more than one. see on_transfer_split below.
|
// reject proposed transactions if there are more than one. see on_transfer_split below.
|
||||||
if (ptx_vector.size() != 1)
|
if (ptx_vector.size() != 1)
|
||||||
|
@ -299,9 +299,9 @@ namespace tools
|
||||||
}
|
}
|
||||||
std::vector<wallet2::pending_tx> ptx_vector;
|
std::vector<wallet2::pending_tx> ptx_vector;
|
||||||
if (req.new_algorithm)
|
if (req.new_algorithm)
|
||||||
ptx_vector = m_wallet.create_transactions_2(dsts, mixin, req.unlock_time, req.fee, extra, req.trusted_daemon);
|
ptx_vector = m_wallet.create_transactions_2(dsts, mixin, req.unlock_time, req.fee_multiplier, extra, req.trusted_daemon);
|
||||||
else
|
else
|
||||||
ptx_vector = m_wallet.create_transactions(dsts, mixin, req.unlock_time, req.fee, extra, req.trusted_daemon);
|
ptx_vector = m_wallet.create_transactions(dsts, mixin, req.unlock_time, req.fee_multiplier, extra, req.trusted_daemon);
|
||||||
|
|
||||||
m_wallet.commit_tx(ptx_vector);
|
m_wallet.commit_tx(ptx_vector);
|
||||||
|
|
||||||
|
@ -406,7 +406,7 @@ namespace tools
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
std::vector<wallet2::pending_tx> ptx_vector = m_wallet.create_transactions_all(dsts[0].addr, req.mixin, req.unlock_time, req.fee, extra, req.trusted_daemon);
|
std::vector<wallet2::pending_tx> ptx_vector = m_wallet.create_transactions_all(dsts[0].addr, req.mixin, req.unlock_time, req.fee_multiplier, extra, req.trusted_daemon);
|
||||||
|
|
||||||
m_wallet.commit_tx(ptx_vector);
|
m_wallet.commit_tx(ptx_vector);
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,7 @@ namespace wallet_rpc
|
||||||
struct request
|
struct request
|
||||||
{
|
{
|
||||||
std::list<transfer_destination> destinations;
|
std::list<transfer_destination> destinations;
|
||||||
uint64_t fee;
|
uint64_t fee_multiplier;
|
||||||
uint64_t mixin;
|
uint64_t mixin;
|
||||||
uint64_t unlock_time;
|
uint64_t unlock_time;
|
||||||
std::string payment_id;
|
std::string payment_id;
|
||||||
|
@ -119,7 +119,7 @@ namespace wallet_rpc
|
||||||
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
KV_SERIALIZE(destinations)
|
KV_SERIALIZE(destinations)
|
||||||
KV_SERIALIZE(fee)
|
KV_SERIALIZE(fee_multiplier)
|
||||||
KV_SERIALIZE(mixin)
|
KV_SERIALIZE(mixin)
|
||||||
KV_SERIALIZE(unlock_time)
|
KV_SERIALIZE(unlock_time)
|
||||||
KV_SERIALIZE(payment_id)
|
KV_SERIALIZE(payment_id)
|
||||||
|
@ -145,7 +145,7 @@ namespace wallet_rpc
|
||||||
struct request
|
struct request
|
||||||
{
|
{
|
||||||
std::list<transfer_destination> destinations;
|
std::list<transfer_destination> destinations;
|
||||||
uint64_t fee;
|
uint64_t fee_multiplier;
|
||||||
uint64_t mixin;
|
uint64_t mixin;
|
||||||
uint64_t unlock_time;
|
uint64_t unlock_time;
|
||||||
std::string payment_id;
|
std::string payment_id;
|
||||||
|
@ -155,7 +155,7 @@ namespace wallet_rpc
|
||||||
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
KV_SERIALIZE(destinations)
|
KV_SERIALIZE(destinations)
|
||||||
KV_SERIALIZE(fee)
|
KV_SERIALIZE(fee_multiplier)
|
||||||
KV_SERIALIZE(mixin)
|
KV_SERIALIZE(mixin)
|
||||||
KV_SERIALIZE(unlock_time)
|
KV_SERIALIZE(unlock_time)
|
||||||
KV_SERIALIZE(payment_id)
|
KV_SERIALIZE(payment_id)
|
||||||
|
@ -207,7 +207,7 @@ namespace wallet_rpc
|
||||||
struct request
|
struct request
|
||||||
{
|
{
|
||||||
std::string address;
|
std::string address;
|
||||||
uint64_t fee;
|
uint64_t fee_multiplier;
|
||||||
uint64_t mixin;
|
uint64_t mixin;
|
||||||
uint64_t unlock_time;
|
uint64_t unlock_time;
|
||||||
std::string payment_id;
|
std::string payment_id;
|
||||||
|
@ -216,7 +216,7 @@ namespace wallet_rpc
|
||||||
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
KV_SERIALIZE(address)
|
KV_SERIALIZE(address)
|
||||||
KV_SERIALIZE(fee)
|
KV_SERIALIZE(fee_multiplier)
|
||||||
KV_SERIALIZE(mixin)
|
KV_SERIALIZE(mixin)
|
||||||
KV_SERIALIZE(unlock_time)
|
KV_SERIALIZE(unlock_time)
|
||||||
KV_SERIALIZE(payment_id)
|
KV_SERIALIZE(payment_id)
|
||||||
|
|
Loading…
Reference in a new issue