aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wallet/wallet2.cpp137
-rw-r--r--src/wallet/wallet2.h2
2 files changed, 129 insertions, 10 deletions
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 83e7e3ed5..3b17c9bc9 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -3981,10 +3981,134 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<crypto
}
}
+
+bool wallet2::tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, uint64_t global_index, const crypto::public_key& tx_public_key, const rct::key& mask, uint64_t real_index, bool unlocked) const
+{
+ if (!unlocked) // don't add locked outs
+ return false;
+ if (global_index == real_index) // don't re-add real one
+ return false;
+ auto item = std::make_tuple(global_index, tx_public_key, mask);
+ if (std::find(outs.back().begin(), outs.back().end(), item) != outs.back().end()) // don't add duplicates
+ return false;
+ outs.back().push_back(item);
+ return true;
+}
+
+void wallet2::light_wallet_get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, const std::list<size_t> &selected_transfers, size_t fake_outputs_count) {
+
+ MDEBUG("LIGHTWALLET - Getting random outs");
+
+ cryptonote::COMMAND_RPC_GET_RANDOM_OUTS::request oreq;
+ cryptonote::COMMAND_RPC_GET_RANDOM_OUTS::response ores;
+
+ size_t light_wallet_requested_outputs_count = (size_t)((fake_outputs_count + 1) * 1.5 + 1);
+
+ // Amounts to ask for
+ // MyMonero api handle amounts and fees as strings
+ for(size_t idx: selected_transfers) {
+ const uint64_t ask_amount = m_transfers[idx].is_rct() ? 0 : m_transfers[idx].amount();
+ std::ostringstream amount_ss;
+ amount_ss << ask_amount;
+ oreq.amounts.push_back(amount_ss.str());
+ }
+
+ oreq.count = light_wallet_requested_outputs_count;
+ m_daemon_rpc_mutex.lock();
+ bool r = epee::net_utils::invoke_http_json("/get_random_outs", oreq, ores, m_http_client, rpc_timeout, "POST");
+ m_daemon_rpc_mutex.unlock();
+ THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_random_outs");
+ THROW_WALLET_EXCEPTION_IF(ores.amount_outs.empty() , error::wallet_internal_error, "No outputs recieved from light wallet node. Error: " + ores.Error);
+
+ // Check if we got enough outputs for each amount
+ for(auto& out: ores.amount_outs) {
+ const uint64_t out_amount = boost::lexical_cast<uint64_t>(out.amount);
+ THROW_WALLET_EXCEPTION_IF(out.outputs.size() < light_wallet_requested_outputs_count , error::wallet_internal_error, "Not enough outputs for amount: " + boost::lexical_cast<std::string>(out.amount));
+ MDEBUG(out.outputs.size() << " outputs for amount "+ boost::lexical_cast<std::string>(out.amount) + " received from light wallet node");
+ }
+
+ MDEBUG("selected transfers size: " << selected_transfers.size());
+
+ for(size_t idx: selected_transfers)
+ {
+ // Create new index
+ outs.push_back(std::vector<get_outs_entry>());
+ outs.back().reserve(fake_outputs_count + 1);
+
+ // add real output first
+ const transfer_details &td = m_transfers[idx];
+ const uint64_t amount = td.is_rct() ? 0 : td.amount();
+ outs.back().push_back(std::make_tuple(td.m_global_output_index, td.get_public_key(), rct::commit(td.amount(), td.m_mask)));
+ MDEBUG("added real output " << string_tools::pod_to_hex(td.get_public_key()));
+
+ // Even if the lightwallet server returns random outputs, we pick them randomly.
+ std::vector<size_t> order;
+ order.resize(light_wallet_requested_outputs_count);
+ for (size_t n = 0; n < order.size(); ++n)
+ order[n] = n;
+ std::shuffle(order.begin(), order.end(), std::default_random_engine(crypto::rand<unsigned>()));
+
+
+ LOG_PRINT_L2("Looking for " << (fake_outputs_count+1) << " outputs with amounts " << print_money(td.is_rct() ? 0 : td.amount()));
+ MDEBUG("OUTS SIZE: " << outs.back().size());
+ for (size_t o = 0; o < light_wallet_requested_outputs_count && outs.back().size() < fake_outputs_count + 1; ++o)
+ {
+ // Random pick
+ size_t i = order[o];
+
+ // Find which random output key to use
+ bool found_amount = false;
+ size_t amount_key;
+ for(amount_key = 0; amount_key < ores.amount_outs.size(); ++amount_key)
+ {
+ if(boost::lexical_cast<uint64_t>(ores.amount_outs[amount_key].amount) == amount) {
+ found_amount = true;
+ break;
+ }
+ }
+ THROW_WALLET_EXCEPTION_IF(!found_amount , error::wallet_internal_error, "Outputs for amount " + boost::lexical_cast<std::string>(ores.amount_outs[amount_key].amount) + " not found" );
+
+ LOG_PRINT_L2("Index " << i << "/" << light_wallet_requested_outputs_count << ": idx " << ores.amount_outs[amount_key].outputs[i].global_index << " (real " << td.m_global_output_index << "), unlocked " << "(always in light)" << ", key " << ores.amount_outs[0].outputs[i].public_key);
+
+ // Convert light wallet string data to proper data structures
+ crypto::public_key tx_public_key;
+ rct::key mask = AUTO_VAL_INIT(mask); // decrypted mask - not used here
+ rct::key rct_commit = AUTO_VAL_INIT(rct_commit);
+ THROW_WALLET_EXCEPTION_IF(string_tools::validate_hex(64, ores.amount_outs[amount_key].outputs[i].public_key), error::wallet_internal_error, "Invalid public_key");
+ string_tools::hex_to_pod(ores.amount_outs[amount_key].outputs[i].public_key, tx_public_key);
+ const uint64_t global_index = ores.amount_outs[amount_key].outputs[i].global_index;
+ if(!light_wallet_parse_rct_str(ores.amount_outs[amount_key].outputs[i].rct, tx_public_key, 0, mask, rct_commit, false))
+ rct_commit = rct::zeroCommit(td.amount());
+
+ if (tx_add_fake_output(outs, global_index, tx_public_key, rct_commit, td.m_global_output_index, true)) {
+ MDEBUG("added fake output " << ores.amount_outs[amount_key].outputs[i].public_key);
+ MDEBUG("index " << global_index);
+ }
+ }
+
+ THROW_WALLET_EXCEPTION_IF(outs.back().size() < fake_outputs_count + 1 , error::wallet_internal_error, "Not enough fake outputs found" );
+
+ // Real output is the first. Shuffle outputs
+ MTRACE(outs.back().size() << " outputs added. Sorting outputs by index:");
+ 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); });
+
+ // Print output order
+ for(auto added_out: outs.back())
+ MTRACE(std::get<0>(added_out));
+
+ }
+}
+
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)
{
LOG_PRINT_L2("fake_outputs_count: " << fake_outputs_count);
outs.clear();
+
+ if(m_light_wallet && fake_outputs_count > 0) {
+ light_wallet_get_outs(outs, selected_transfers, fake_outputs_count);
+ return;
+ }
+
if (fake_outputs_count > 0)
{
// get histogram for the amounts we need
@@ -4181,14 +4305,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
{
size_t i = base + order[o];
LOG_PRINT_L2("Index " << i << "/" << requested_outputs_count << ": idx " << req.outputs[i].index << " (real " << td.m_global_output_index << "), unlocked " << daemon_resp.outs[i].unlocked << ", key " << daemon_resp.outs[i].key);
- if (req.outputs[i].index == td.m_global_output_index) // don't re-add real one
- continue;
- if (!daemon_resp.outs[i].unlocked) // don't add locked outs
- continue;
- auto item = std::make_tuple(req.outputs[i].index, daemon_resp.outs[i].key, daemon_resp.outs[i].mask);
- if (std::find(outs.back().begin(), outs.back().end(), item) != outs.back().end()) // don't add duplicates
- continue;
- outs.back().push_back(item);
+ tx_add_fake_output(outs, req.outputs[i].index, daemon_resp.outs[i].key, daemon_resp.outs[i].mask, td.m_global_output_index, daemon_resp.outs[i].unlocked);
}
if (outs.back().size() < fake_outputs_count + 1)
{
@@ -4210,7 +4327,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
const transfer_details &td = m_transfers[idx];
std::vector<get_outs_entry> v;
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, td.get_public_key(), mask));
outs.push_back(v);
}
}
@@ -4446,7 +4563,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
tx_output_entry real_oe;
real_oe.first = td.m_global_output_index;
- real_oe.second.dest = rct::pk2rct(boost::get<txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key);
+ real_oe.second.dest = rct::pk2rct(td.get_public_key());
real_oe.second.mask = rct::commit(td.amount(), td.m_mask);
*it_to_replace = real_oe;
src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_tx, td.m_pk_index);
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 983b448d6..e8a30dba9 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -796,6 +796,8 @@ namespace tools
void set_spent(size_t idx, uint64_t height);
void set_unspent(size_t idx);
void get_outs(std::vector<std::vector<get_outs_entry>> &outs, const std::list<size_t> &selected_transfers, size_t fake_outputs_count);
+ bool tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, uint64_t global_index, const crypto::public_key& tx_public_key, const rct::key& mask, uint64_t real_index, bool unlocked) const;
+ 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;
bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &unused_dust_indices) const;
std::vector<size_t> get_only_rct(const std::vector<size_t> &unused_dust_indices, const std::vector<size_t> &unused_transfers_indices) const;