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:
moneromooo-monero 2017-01-07 16:06:07 +00:00
parent 64da0983d5
commit d86ae2bec6
No known key found for this signature in database
GPG Key ID: 686F07454D6CEFC3
3 changed files with 55 additions and 23 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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)