wallet2: reuse fake outs when adjusting fee on transfer
This avoids indirectly leaking the real output to the daemon, and is faster. This will still happen for more complex cases, especially when cancelling a tx and "re-rolling" it.
This commit is contained in:
parent
64da0983d5
commit
d86ae2bec6
3 changed files with 55 additions and 23 deletions
|
@ -3400,8 +3400,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<crypto
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename entry>
|
void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, const std::list<size_t> &selected_transfers, size_t fake_outputs_count)
|
||||||
void wallet2::get_outs(std::vector<std::vector<entry>> &outs, const std::list<size_t> &selected_transfers, size_t fake_outputs_count)
|
|
||||||
{
|
{
|
||||||
LOG_PRINT_L2("fake_outputs_count: " << fake_outputs_count);
|
LOG_PRINT_L2("fake_outputs_count: " << fake_outputs_count);
|
||||||
outs.clear();
|
outs.clear();
|
||||||
|
@ -3492,6 +3491,7 @@ void wallet2::get_outs(std::vector<std::vector<entry>> &outs, const std::list<si
|
||||||
uint64_t num_found = 1;
|
uint64_t num_found = 1;
|
||||||
seen_indices.emplace(td.m_global_output_index);
|
seen_indices.emplace(td.m_global_output_index);
|
||||||
req.outputs.push_back({amount, td.m_global_output_index});
|
req.outputs.push_back({amount, td.m_global_output_index});
|
||||||
|
LOG_PRINT_L1("Selecting real output: " << td.m_global_output_index << " for " << print_money(amount));
|
||||||
|
|
||||||
// while we still need more mixins
|
// while we still need more mixins
|
||||||
while (num_found < requested_outputs_count)
|
while (num_found < requested_outputs_count)
|
||||||
|
@ -3563,7 +3563,7 @@ void wallet2::get_outs(std::vector<std::vector<entry>> &outs, const std::list<si
|
||||||
{
|
{
|
||||||
const transfer_details &td = m_transfers[idx];
|
const transfer_details &td = m_transfers[idx];
|
||||||
size_t requested_outputs_count = base_requested_outputs_count + (td.is_rct() ? CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW - CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE : 0);
|
size_t requested_outputs_count = base_requested_outputs_count + (td.is_rct() ? CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW - CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE : 0);
|
||||||
outs.push_back(std::vector<entry>());
|
outs.push_back(std::vector<get_outs_entry>());
|
||||||
outs.back().reserve(fake_outputs_count + 1);
|
outs.back().reserve(fake_outputs_count + 1);
|
||||||
const rct::key mask = td.is_rct() ? rct::commit(td.amount(), td.m_mask) : rct::zeroCommit(td.amount());
|
const rct::key mask = td.is_rct() ? rct::commit(td.amount(), td.m_mask) : rct::zeroCommit(td.amount());
|
||||||
|
|
||||||
|
@ -3616,7 +3616,7 @@ void wallet2::get_outs(std::vector<std::vector<entry>> &outs, const std::list<si
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// sort the subsection, so any spares are reset in order
|
// sort the subsection, so any spares are reset in order
|
||||||
std::sort(outs.back().begin(), outs.back().end(), [](const entry &a, const entry &b) { return std::get<0>(a) < std::get<0>(b); });
|
std::sort(outs.back().begin(), outs.back().end(), [](const get_outs_entry &a, const get_outs_entry &b) { return std::get<0>(a) < std::get<0>(b); });
|
||||||
}
|
}
|
||||||
base += requested_outputs_count;
|
base += requested_outputs_count;
|
||||||
}
|
}
|
||||||
|
@ -3627,7 +3627,7 @@ void wallet2::get_outs(std::vector<std::vector<entry>> &outs, const std::list<si
|
||||||
for (size_t idx: selected_transfers)
|
for (size_t idx: selected_transfers)
|
||||||
{
|
{
|
||||||
const transfer_details &td = m_transfers[idx];
|
const transfer_details &td = m_transfers[idx];
|
||||||
std::vector<entry> v;
|
std::vector<get_outs_entry> v;
|
||||||
const rct::key mask = td.is_rct() ? rct::commit(td.amount(), td.m_mask) : rct::zeroCommit(td.amount());
|
const rct::key mask = td.is_rct() ? rct::commit(td.amount(), td.m_mask) : rct::zeroCommit(td.amount());
|
||||||
v.push_back(std::make_tuple(td.m_global_output_index, boost::get<txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key, mask));
|
v.push_back(std::make_tuple(td.m_global_output_index, boost::get<txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key, mask));
|
||||||
outs.push_back(v);
|
outs.push_back(v);
|
||||||
|
@ -3636,7 +3636,8 @@ void wallet2::get_outs(std::vector<std::vector<entry>> &outs, const std::list<si
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_entry>& dsts, const std::list<size_t> selected_transfers, size_t fake_outputs_count,
|
void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_entry>& dsts, const std::list<size_t> selected_transfers, size_t fake_outputs_count,
|
||||||
|
std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs,
|
||||||
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx)
|
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx)
|
||||||
{
|
{
|
||||||
using namespace cryptonote;
|
using namespace cryptonote;
|
||||||
|
@ -3666,11 +3667,11 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
|
||||||
LOG_PRINT_L2("wanted " << print_money(needed_money) << ", found " << print_money(found_money) << ", fee " << print_money(fee));
|
LOG_PRINT_L2("wanted " << print_money(needed_money) << ", found " << print_money(found_money) << ", fee " << print_money(fee));
|
||||||
THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_money, found_money, needed_money - fee, fee);
|
THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_money, found_money, needed_money - fee, fee);
|
||||||
|
|
||||||
typedef std::tuple<uint64_t, crypto::public_key, rct::key> entry;
|
if (outs.empty())
|
||||||
std::vector<std::vector<entry>> outs;
|
get_outs(outs, selected_transfers, fake_outputs_count); // may throw
|
||||||
get_outs(outs, selected_transfers, fake_outputs_count); // may throw
|
|
||||||
|
|
||||||
//prepare inputs
|
//prepare inputs
|
||||||
|
LOG_PRINT_L2("preparing outputs");
|
||||||
typedef cryptonote::tx_source_entry::output_entry tx_output_entry;
|
typedef cryptonote::tx_source_entry::output_entry tx_output_entry;
|
||||||
size_t i = 0, out_index = 0;
|
size_t i = 0, out_index = 0;
|
||||||
std::vector<cryptonote::tx_source_entry> sources;
|
std::vector<cryptonote::tx_source_entry> sources;
|
||||||
|
@ -3713,6 +3714,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
|
||||||
detail::print_source_entry(src);
|
detail::print_source_entry(src);
|
||||||
++out_index;
|
++out_index;
|
||||||
}
|
}
|
||||||
|
LOG_PRINT_L2("outputs prepared");
|
||||||
|
|
||||||
cryptonote::tx_destination_entry change_dts = AUTO_VAL_INIT(change_dts);
|
cryptonote::tx_destination_entry change_dts = AUTO_VAL_INIT(change_dts);
|
||||||
if (needed_money < found_money)
|
if (needed_money < found_money)
|
||||||
|
@ -3735,7 +3737,9 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
|
||||||
}
|
}
|
||||||
|
|
||||||
crypto::secret_key tx_key;
|
crypto::secret_key tx_key;
|
||||||
|
LOG_PRINT_L2("constructing tx");
|
||||||
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), sources, splitted_dsts, extra, tx, unlock_time, tx_key);
|
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), sources, splitted_dsts, extra, tx, unlock_time, tx_key);
|
||||||
|
LOG_PRINT_L2("constructed tx, r="<<r);
|
||||||
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_testnet);
|
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_testnet);
|
||||||
THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit);
|
THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit);
|
||||||
|
|
||||||
|
@ -3771,9 +3775,11 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
|
||||||
ptx.construction_data.unlock_time = unlock_time;
|
ptx.construction_data.unlock_time = unlock_time;
|
||||||
ptx.construction_data.use_rct = false;
|
ptx.construction_data.use_rct = false;
|
||||||
ptx.construction_data.dests = dsts;
|
ptx.construction_data.dests = dsts;
|
||||||
|
LOG_PRINT_L2("transfer_selected done");
|
||||||
}
|
}
|
||||||
|
|
||||||
void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry> dsts, const std::list<size_t> selected_transfers, size_t fake_outputs_count,
|
void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry> dsts, const std::list<size_t> selected_transfers, size_t fake_outputs_count,
|
||||||
|
std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs,
|
||||||
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx)
|
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx)
|
||||||
{
|
{
|
||||||
using namespace cryptonote;
|
using namespace cryptonote;
|
||||||
|
@ -3782,7 +3788,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
|
||||||
|
|
||||||
uint64_t upper_transaction_size_limit = get_upper_tranaction_size_limit();
|
uint64_t upper_transaction_size_limit = get_upper_tranaction_size_limit();
|
||||||
uint64_t needed_money = fee;
|
uint64_t needed_money = fee;
|
||||||
LOG_PRINT_L2("transfer: starting with fee " << print_money (needed_money));
|
LOG_PRINT_L2("transfer_selected_rct: starting with fee " << print_money (needed_money));
|
||||||
LOG_PRINT_L0("selected transfers: ");
|
LOG_PRINT_L0("selected transfers: ");
|
||||||
for (auto t: selected_transfers)
|
for (auto t: selected_transfers)
|
||||||
LOG_PRINT_L2(" " << t);
|
LOG_PRINT_L2(" " << t);
|
||||||
|
@ -3806,11 +3812,11 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
|
||||||
LOG_PRINT_L2("wanted " << print_money(needed_money) << ", found " << print_money(found_money) << ", fee " << print_money(fee));
|
LOG_PRINT_L2("wanted " << print_money(needed_money) << ", found " << print_money(found_money) << ", fee " << print_money(fee));
|
||||||
THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_money, found_money, needed_money - fee, fee);
|
THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_money, found_money, needed_money - fee, fee);
|
||||||
|
|
||||||
typedef std::tuple<uint64_t, crypto::public_key, rct::key> entry;
|
if (outs.empty())
|
||||||
std::vector<std::vector<entry>> outs;
|
get_outs(outs, selected_transfers, fake_outputs_count); // may throw
|
||||||
get_outs(outs, selected_transfers, fake_outputs_count); // may throw
|
|
||||||
|
|
||||||
//prepare inputs
|
//prepare inputs
|
||||||
|
LOG_PRINT_L2("preparing outputs");
|
||||||
size_t i = 0, out_index = 0;
|
size_t i = 0, out_index = 0;
|
||||||
std::vector<cryptonote::tx_source_entry> sources;
|
std::vector<cryptonote::tx_source_entry> sources;
|
||||||
BOOST_FOREACH(size_t idx, selected_transfers)
|
BOOST_FOREACH(size_t idx, selected_transfers)
|
||||||
|
@ -3853,6 +3859,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
|
||||||
detail::print_source_entry(src);
|
detail::print_source_entry(src);
|
||||||
++out_index;
|
++out_index;
|
||||||
}
|
}
|
||||||
|
LOG_PRINT_L2("outputs prepared");
|
||||||
|
|
||||||
// we still keep a copy, since we want to keep dsts free of change for user feedback purposes
|
// we still keep a copy, since we want to keep dsts free of change for user feedback purposes
|
||||||
std::vector<cryptonote::tx_destination_entry> splitted_dsts = dsts;
|
std::vector<cryptonote::tx_destination_entry> splitted_dsts = dsts;
|
||||||
|
@ -3864,9 +3871,11 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
|
||||||
// the sender with a 0 amount output. We send a 0 amount in order to avoid
|
// the sender with a 0 amount output. We send a 0 amount in order to avoid
|
||||||
// letting the destination be able to work out which of the inputs is the
|
// letting the destination be able to work out which of the inputs is the
|
||||||
// real one in our rings
|
// real one in our rings
|
||||||
|
LOG_PRINT_L2("generating dummy address for 0 change");
|
||||||
cryptonote::account_base dummy;
|
cryptonote::account_base dummy;
|
||||||
dummy.generate();
|
dummy.generate();
|
||||||
change_dts.addr = dummy.get_keys().m_account_address;
|
change_dts.addr = dummy.get_keys().m_account_address;
|
||||||
|
LOG_PRINT_L2("generated dummy address for 0 change");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3875,10 +3884,13 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
|
||||||
splitted_dsts.push_back(change_dts);
|
splitted_dsts.push_back(change_dts);
|
||||||
|
|
||||||
crypto::secret_key tx_key;
|
crypto::secret_key tx_key;
|
||||||
|
LOG_PRINT_L2("constructing tx");
|
||||||
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), sources, splitted_dsts, extra, tx, unlock_time, tx_key, true);
|
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), sources, splitted_dsts, extra, tx, unlock_time, tx_key, true);
|
||||||
|
LOG_PRINT_L2("constructed tx, r="<<r);
|
||||||
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, dsts, unlock_time, m_testnet);
|
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, dsts, unlock_time, m_testnet);
|
||||||
THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit);
|
THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit);
|
||||||
|
|
||||||
|
LOG_PRINT_L2("gathering key images");
|
||||||
std::string key_images;
|
std::string key_images;
|
||||||
bool all_are_txin_to_key = std::all_of(tx.vin.begin(), tx.vin.end(), [&](const txin_v& s_e) -> bool
|
bool all_are_txin_to_key = std::all_of(tx.vin.begin(), tx.vin.end(), [&](const txin_v& s_e) -> bool
|
||||||
{
|
{
|
||||||
|
@ -3887,6 +3899,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
THROW_WALLET_EXCEPTION_IF(!all_are_txin_to_key, error::unexpected_txin_type, tx);
|
THROW_WALLET_EXCEPTION_IF(!all_are_txin_to_key, error::unexpected_txin_type, tx);
|
||||||
|
LOG_PRINT_L2("gathered key images");
|
||||||
|
|
||||||
ptx.key_images = key_images;
|
ptx.key_images = key_images;
|
||||||
ptx.fee = fee;
|
ptx.fee = fee;
|
||||||
|
@ -3905,6 +3918,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
|
||||||
ptx.construction_data.unlock_time = unlock_time;
|
ptx.construction_data.unlock_time = unlock_time;
|
||||||
ptx.construction_data.use_rct = true;
|
ptx.construction_data.use_rct = true;
|
||||||
ptx.construction_data.dests = dsts;
|
ptx.construction_data.dests = dsts;
|
||||||
|
LOG_PRINT_L2("transfer_selected_rct done");
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs)
|
static size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs)
|
||||||
|
@ -4106,12 +4120,14 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||||
accumulated_change = 0;
|
accumulated_change = 0;
|
||||||
adding_fee = false;
|
adding_fee = false;
|
||||||
needed_fee = 0;
|
needed_fee = 0;
|
||||||
|
std::vector<std::vector<tools::wallet2::get_outs_entry>> outs;
|
||||||
|
|
||||||
// for rct, since we don't see the amounts, we will try to make all transactions
|
// for rct, since we don't see the amounts, we will try to make all transactions
|
||||||
// look the same, with 1 or 2 inputs, and 2 outputs. One input is preferable, as
|
// look the same, with 1 or 2 inputs, and 2 outputs. One input is preferable, as
|
||||||
// this prevents linking to another by provenance analysis, but two is ok if we
|
// this prevents linking to another by provenance analysis, but two is ok if we
|
||||||
// try to pick outputs not from the same block. We will get two outputs, one for
|
// try to pick outputs not from the same block. We will get two outputs, one for
|
||||||
// the destination, and one for change.
|
// the destination, and one for change.
|
||||||
|
LOG_PRINT_L2("checking preferred");
|
||||||
std::vector<size_t> prefered_inputs;
|
std::vector<size_t> prefered_inputs;
|
||||||
uint64_t rct_outs_needed = 2 * (fake_outs_count + 1);
|
uint64_t rct_outs_needed = 2 * (fake_outs_count + 1);
|
||||||
rct_outs_needed += 100; // some fudge factor since we don't know how many are locked
|
rct_outs_needed += 100; // some fudge factor since we don't know how many are locked
|
||||||
|
@ -4128,6 +4144,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||||
LOG_PRINT_L1("Found prefered rct inputs for rct tx: " << s);
|
LOG_PRINT_L1("Found prefered rct inputs for rct tx: " << s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
LOG_PRINT_L2("done checking preferred");
|
||||||
|
|
||||||
// while:
|
// while:
|
||||||
// - we have something to send
|
// - we have something to send
|
||||||
|
@ -4161,6 +4178,9 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||||
uint64_t available_amount = td.amount();
|
uint64_t available_amount = td.amount();
|
||||||
accumulated_outputs += available_amount;
|
accumulated_outputs += available_amount;
|
||||||
|
|
||||||
|
// clear any fake outs we'd already gathered, since we'll need a new set
|
||||||
|
outs.clear();
|
||||||
|
|
||||||
if (adding_fee)
|
if (adding_fee)
|
||||||
{
|
{
|
||||||
LOG_PRINT_L2("We need more fee, adding it to fee");
|
LOG_PRINT_L2("We need more fee, adding it to fee");
|
||||||
|
@ -4217,10 +4237,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||||
LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " destinations and " <<
|
LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " destinations and " <<
|
||||||
tx.selected_transfers.size() << " outputs");
|
tx.selected_transfers.size() << " outputs");
|
||||||
if (use_rct)
|
if (use_rct)
|
||||||
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, unlock_time, needed_fee, extra,
|
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
|
||||||
test_tx, test_ptx);
|
test_tx, test_ptx);
|
||||||
else
|
else
|
||||||
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, outs, 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(fee_per_kb, txBlob, fee_multiplier);
|
needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier);
|
||||||
|
@ -4260,10 +4280,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||||
LOG_PRINT_L2("We made a tx, adjusting fee and saving it");
|
LOG_PRINT_L2("We made a tx, adjusting fee and saving it");
|
||||||
do {
|
do {
|
||||||
if (use_rct)
|
if (use_rct)
|
||||||
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, unlock_time, needed_fee, extra,
|
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
|
||||||
test_tx, test_ptx);
|
test_tx, test_ptx);
|
||||||
else
|
else
|
||||||
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, outs, 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(fee_per_kb, txBlob, fee_multiplier);
|
needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier);
|
||||||
|
@ -4351,6 +4371,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
||||||
std::vector<TX> txes;
|
std::vector<TX> txes;
|
||||||
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();
|
||||||
|
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 bool use_new_fee = use_fork_rules(3, -720 * 14);
|
||||||
|
@ -4386,6 +4407,9 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
||||||
uint64_t available_amount = td.amount();
|
uint64_t available_amount = td.amount();
|
||||||
accumulated_outputs += available_amount;
|
accumulated_outputs += available_amount;
|
||||||
|
|
||||||
|
// clear any fake outs we'd already gathered, since we'll need a new set
|
||||||
|
outs.clear();
|
||||||
|
|
||||||
// here, check if we need to sent tx and start a new one
|
// here, check if we need to sent tx and start a new one
|
||||||
LOG_PRINT_L2("Considering whether to create a tx now, " << tx.selected_transfers.size() << " inputs, tx limit "
|
LOG_PRINT_L2("Considering whether to create a tx now, " << tx.selected_transfers.size() << " inputs, tx limit "
|
||||||
<< upper_transaction_size_limit);
|
<< upper_transaction_size_limit);
|
||||||
|
@ -4407,10 +4431,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
||||||
LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " destinations and " <<
|
LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " destinations and " <<
|
||||||
tx.selected_transfers.size() << " outputs");
|
tx.selected_transfers.size() << " outputs");
|
||||||
if (use_rct)
|
if (use_rct)
|
||||||
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, unlock_time, needed_fee, extra,
|
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
|
||||||
test_tx, test_ptx);
|
test_tx, test_ptx);
|
||||||
else
|
else
|
||||||
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, outs, 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(fee_per_kb, txBlob, fee_multiplier);
|
needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier);
|
||||||
|
@ -4424,10 +4448,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
||||||
LOG_PRINT_L2("We made a tx, adjusting fee and saving it");
|
LOG_PRINT_L2("We made a tx, adjusting fee and saving it");
|
||||||
tx.dsts[0].amount = available_for_fee - needed_fee;
|
tx.dsts[0].amount = available_for_fee - needed_fee;
|
||||||
if (use_rct)
|
if (use_rct)
|
||||||
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, unlock_time, needed_fee, extra,
|
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
|
||||||
test_tx, test_ptx);
|
test_tx, test_ptx);
|
||||||
else
|
else
|
||||||
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, outs, 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(fee_per_kb, txBlob, fee_multiplier);
|
needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier);
|
||||||
|
|
|
@ -275,6 +275,8 @@ namespace tools
|
||||||
std::string m_description;
|
std::string m_description;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef std::tuple<uint64_t, crypto::public_key, rct::key> get_outs_entry;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Generates a wallet or restores one.
|
* \brief Generates a wallet or restores one.
|
||||||
* \param wallet_ Name of wallet file
|
* \param wallet_ Name of wallet file
|
||||||
|
@ -387,8 +389,10 @@ namespace tools
|
||||||
void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, const size_t fake_outputs_count, const std::vector<size_t> &unused_transfers_indices, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx& ptx, bool trusted_daemon);
|
void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, const size_t fake_outputs_count, const std::vector<size_t> &unused_transfers_indices, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx& ptx, bool trusted_daemon);
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void transfer_selected(const std::vector<cryptonote::tx_destination_entry>& dsts, const std::list<size_t> selected_transfers, size_t fake_outputs_count,
|
void transfer_selected(const std::vector<cryptonote::tx_destination_entry>& dsts, const std::list<size_t> selected_transfers, size_t fake_outputs_count,
|
||||||
|
std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs,
|
||||||
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx);
|
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx);
|
||||||
void transfer_selected_rct(std::vector<cryptonote::tx_destination_entry> dsts, const std::list<size_t> selected_transfers, size_t fake_outputs_count,
|
void transfer_selected_rct(std::vector<cryptonote::tx_destination_entry> dsts, const std::list<size_t> selected_transfers, size_t fake_outputs_count,
|
||||||
|
std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs,
|
||||||
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx);
|
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx);
|
||||||
|
|
||||||
void commit_tx(pending_tx& ptx_vector);
|
void commit_tx(pending_tx& ptx_vector);
|
||||||
|
@ -607,8 +611,7 @@ namespace tools
|
||||||
std::vector<size_t> pick_preferred_rct_inputs(uint64_t needed_money) const;
|
std::vector<size_t> pick_preferred_rct_inputs(uint64_t needed_money) const;
|
||||||
void set_spent(size_t idx, uint64_t height);
|
void set_spent(size_t idx, uint64_t height);
|
||||||
void set_unspent(size_t idx);
|
void set_unspent(size_t idx);
|
||||||
template<typename entry>
|
void get_outs(std::vector<std::vector<get_outs_entry>> &outs, const std::list<size_t> &selected_transfers, size_t fake_outputs_count);
|
||||||
void get_outs(std::vector<std::vector<entry>> &outs, const std::list<size_t> &selected_transfers, size_t fake_outputs_count);
|
|
||||||
bool wallet_generate_key_image_helper(const cryptonote::account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, cryptonote::keypair& in_ephemeral, crypto::key_image& ki);
|
bool wallet_generate_key_image_helper(const cryptonote::account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, cryptonote::keypair& in_ephemeral, crypto::key_image& ki);
|
||||||
crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const;
|
crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const;
|
||||||
|
|
||||||
|
|
|
@ -396,6 +396,7 @@ namespace tools
|
||||||
std::vector<cryptonote::tx_destination_entry> dsts;
|
std::vector<cryptonote::tx_destination_entry> dsts;
|
||||||
std::vector<uint8_t> extra;
|
std::vector<uint8_t> extra;
|
||||||
|
|
||||||
|
LOG_PRINT_L3("on_transfer_split starts");
|
||||||
if (m_wallet.restricted())
|
if (m_wallet.restricted())
|
||||||
{
|
{
|
||||||
er.code = WALLET_RPC_ERROR_CODE_DENIED;
|
er.code = WALLET_RPC_ERROR_CODE_DENIED;
|
||||||
|
@ -485,9 +486,13 @@ namespace tools
|
||||||
mixin = 2;
|
mixin = 2;
|
||||||
}
|
}
|
||||||
std::vector<wallet2::pending_tx> ptx_vector;
|
std::vector<wallet2::pending_tx> ptx_vector;
|
||||||
|
LOG_PRINT_L2("on_transfer_split calling create_transactions_2");
|
||||||
ptx_vector = m_wallet.create_transactions_2(dsts, mixin, req.unlock_time, req.priority, extra, req.trusted_daemon);
|
ptx_vector = m_wallet.create_transactions_2(dsts, mixin, req.unlock_time, req.priority, extra, req.trusted_daemon);
|
||||||
|
LOG_PRINT_L2("on_transfer_split called create_transactions_2");
|
||||||
|
|
||||||
|
LOG_PRINT_L2("on_transfer_split calling commit_txyy");
|
||||||
m_wallet.commit_tx(ptx_vector);
|
m_wallet.commit_tx(ptx_vector);
|
||||||
|
LOG_PRINT_L2("on_transfer_split called commit_txyy");
|
||||||
|
|
||||||
// populate response with tx hashes
|
// populate response with tx hashes
|
||||||
for (auto & ptx : ptx_vector)
|
for (auto & ptx : ptx_vector)
|
||||||
|
|
Loading…
Reference in a new issue