mirror of
https://github.com/monero-project/monero.git
synced 2024-11-17 16:27:39 +00:00
wallet2: get_outs lightwallet support
This commit is contained in:
parent
1197cb71e9
commit
ce61b8189b
2 changed files with 129 additions and 10 deletions
|
@ -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)
|
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);
|
LOG_PRINT_L2("fake_outputs_count: " << fake_outputs_count);
|
||||||
outs.clear();
|
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)
|
if (fake_outputs_count > 0)
|
||||||
{
|
{
|
||||||
// get histogram for the amounts we need
|
// 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];
|
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);
|
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
|
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);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
if (outs.back().size() < fake_outputs_count + 1)
|
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];
|
const transfer_details &td = m_transfers[idx];
|
||||||
std::vector<get_outs_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, td.get_public_key(), mask));
|
||||||
outs.push_back(v);
|
outs.push_back(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4446,7 +4563,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
|
||||||
|
|
||||||
tx_output_entry real_oe;
|
tx_output_entry real_oe;
|
||||||
real_oe.first = td.m_global_output_index;
|
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);
|
real_oe.second.mask = rct::commit(td.amount(), td.m_mask);
|
||||||
*it_to_replace = real_oe;
|
*it_to_replace = real_oe;
|
||||||
src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_tx, td.m_pk_index);
|
src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_tx, td.m_pk_index);
|
||||||
|
|
|
@ -796,6 +796,8 @@ namespace tools
|
||||||
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);
|
||||||
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<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;
|
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;
|
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;
|
std::vector<size_t> get_only_rct(const std::vector<size_t> &unused_dust_indices, const std::vector<size_t> &unused_transfers_indices) const;
|
||||||
|
|
Loading…
Reference in a new issue