mirror of
https://github.com/monero-project/monero.git
synced 2024-11-17 08:17:37 +00:00
wallet2: remember which output keys map to which key images
This allows filling in transfer_details when a cold signed tx gets seen in a block next
This commit is contained in:
parent
6285c43ffc
commit
0debe7d7d3
2 changed files with 101 additions and 16 deletions
|
@ -1681,7 +1681,25 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
|||
td.m_txid = txid;
|
||||
td.m_key_image = tx_scan_info[o].ki;
|
||||
td.m_key_image_known = !m_watch_only && !m_multisig;
|
||||
td.m_key_image_requested = false;
|
||||
if (!td.m_key_image_known)
|
||||
{
|
||||
// we might have cold signed, and have a mapping to key images
|
||||
std::unordered_map<crypto::public_key, crypto::key_image>::const_iterator i = m_cold_key_images.find(tx_scan_info[o].in_ephemeral.pub);
|
||||
if (i != m_cold_key_images.end())
|
||||
{
|
||||
td.m_key_image = i->second;
|
||||
td.m_key_image_known = true;
|
||||
}
|
||||
}
|
||||
if (m_watch_only)
|
||||
{
|
||||
// for view wallets, that flag means "we want to request it"
|
||||
td.m_key_image_request = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
td.m_key_image_request = false;
|
||||
}
|
||||
td.m_key_image_partial = m_multisig;
|
||||
td.m_amount = amount;
|
||||
td.m_pk_index = pk_index - 1;
|
||||
|
@ -1703,7 +1721,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
|||
td.m_rct = false;
|
||||
}
|
||||
set_unspent(m_transfers.size()-1);
|
||||
if (!m_multisig && !m_watch_only)
|
||||
if (td.m_key_image_known)
|
||||
m_key_images[td.m_key_image] = m_transfers.size()-1;
|
||||
m_pub_keys[tx_scan_info[o].in_ephemeral.pub] = m_transfers.size()-1;
|
||||
if (output_tracker_cache)
|
||||
|
@ -5924,6 +5942,61 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector<wallet2::pendin
|
|||
txs.back().additional_tx_keys = additional_tx_keys;
|
||||
}
|
||||
|
||||
// add key image mapping for these txes
|
||||
const account_keys &keys = get_account().get_keys();
|
||||
hw::device &hwdev = m_account.get_device();
|
||||
for (size_t n = 0; n < exported_txs.txes.size(); ++n)
|
||||
{
|
||||
const cryptonote::transaction &tx = signed_txes.ptx[n].tx;
|
||||
|
||||
crypto::key_derivation derivation;
|
||||
std::vector<crypto::key_derivation> additional_derivations;
|
||||
|
||||
// compute public keys from out secret keys
|
||||
crypto::public_key tx_pub_key;
|
||||
crypto::secret_key_to_public_key(txs[n].tx_key, tx_pub_key);
|
||||
std::vector<crypto::public_key> additional_tx_pub_keys;
|
||||
for (const crypto::secret_key &skey: txs[n].additional_tx_keys)
|
||||
{
|
||||
additional_tx_pub_keys.resize(additional_tx_pub_keys.size() + 1);
|
||||
crypto::secret_key_to_public_key(skey, additional_tx_pub_keys.back());
|
||||
}
|
||||
|
||||
// compute derivations
|
||||
hwdev.set_mode(hw::device::TRANSACTION_PARSE);
|
||||
if (!hwdev.generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation))
|
||||
{
|
||||
MWARNING("Failed to generate key derivation from tx pubkey in " << cryptonote::get_transaction_hash(tx) << ", skipping");
|
||||
static_assert(sizeof(derivation) == sizeof(rct::key), "Mismatched sizes of key_derivation and rct::key");
|
||||
memcpy(&derivation, rct::identity().bytes, sizeof(derivation));
|
||||
}
|
||||
for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i)
|
||||
{
|
||||
additional_derivations.push_back({});
|
||||
if (!hwdev.generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back()))
|
||||
{
|
||||
MWARNING("Failed to generate key derivation from additional tx pubkey in " << cryptonote::get_transaction_hash(tx) << ", skipping");
|
||||
memcpy(&additional_derivations.back(), rct::identity().bytes, sizeof(crypto::key_derivation));
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < tx.vout.size(); ++i)
|
||||
{
|
||||
if (tx.vout[i].target.type() != typeid(cryptonote::txout_to_key))
|
||||
continue;
|
||||
const cryptonote::txout_to_key &out = boost::get<cryptonote::txout_to_key>(tx.vout[i].target);
|
||||
// if this output is back to this wallet, we can calculate its key image already
|
||||
if (!is_out_to_acc_precomp(m_subaddresses, out.key, derivation, additional_derivations, i, hwdev))
|
||||
continue;
|
||||
crypto::key_image ki;
|
||||
cryptonote::keypair in_ephemeral;
|
||||
if (generate_key_image_helper(keys, m_subaddresses, out.key, tx_pub_key, additional_tx_pub_keys, i, in_ephemeral, ki, hwdev))
|
||||
signed_txes.tx_key_images[out.key] = ki;
|
||||
else
|
||||
MERROR("Failed to calculate key image");
|
||||
}
|
||||
}
|
||||
|
||||
// add key images
|
||||
signed_txes.key_images.resize(m_transfers.size());
|
||||
for (size_t i = 0; i < m_transfers.size(); ++i)
|
||||
|
@ -6086,6 +6159,10 @@ bool wallet2::parse_tx_from_str(const std::string &signed_tx_st, std::vector<too
|
|||
bool r = import_key_images(signed_txs.key_images);
|
||||
if (!r) return false;
|
||||
|
||||
// remember key images for this tx, for when we get those txes from the blockchain
|
||||
for (const auto &e: signed_txs.tx_key_images)
|
||||
m_cold_key_images.insert(e);
|
||||
|
||||
ptx = signed_txs.ptx;
|
||||
|
||||
return true;
|
||||
|
@ -8284,7 +8361,7 @@ void wallet2::light_wallet_get_unspent_outs()
|
|||
|
||||
td.m_key_image = unspent_key_image;
|
||||
td.m_key_image_known = !m_watch_only && !m_multisig;
|
||||
td.m_key_image_requested = false;
|
||||
td.m_key_image_request = false;
|
||||
td.m_key_image_partial = m_multisig;
|
||||
td.m_amount = o.amount;
|
||||
td.m_pk_index = 0;
|
||||
|
@ -10894,7 +10971,7 @@ std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>>
|
|||
size_t offset = 0;
|
||||
if (!all)
|
||||
{
|
||||
while (offset < m_transfers.size() && !m_transfers[offset].m_key_image_requested)
|
||||
while (offset < m_transfers.size() && !m_transfers[offset].m_key_image_request)
|
||||
++offset;
|
||||
}
|
||||
|
||||
|
@ -11054,7 +11131,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
|
|||
m_transfers[n + offset].m_key_image = signed_key_images[n].first;
|
||||
m_key_images[m_transfers[n + offset].m_key_image] = n + offset;
|
||||
m_transfers[n + offset].m_key_image_known = true;
|
||||
m_transfers[n + offset].m_key_image_requested = false;
|
||||
m_transfers[n + offset].m_key_image_request = false;
|
||||
m_transfers[n + offset].m_key_image_partial = false;
|
||||
}
|
||||
PERF_TIMER_STOP(import_key_images_B);
|
||||
|
@ -11273,7 +11350,7 @@ bool wallet2::import_key_images(std::vector<crypto::key_image> key_images)
|
|||
td.m_key_image = key_images[i];
|
||||
m_key_images[m_transfers[i].m_key_image] = i;
|
||||
td.m_key_image_known = true;
|
||||
td.m_key_image_requested = false;
|
||||
td.m_key_image_request = false;
|
||||
td.m_key_image_partial = false;
|
||||
m_pub_keys[m_transfers[i].get_public_key()] = i;
|
||||
}
|
||||
|
@ -11345,7 +11422,7 @@ std::pair<size_t, std::vector<tools::wallet2::transfer_details>> wallet2::export
|
|||
std::vector<tools::wallet2::transfer_details> outs;
|
||||
|
||||
size_t offset = 0;
|
||||
while (offset < m_transfers.size() && m_transfers[offset].m_key_image_known)
|
||||
while (offset < m_transfers.size() && (m_transfers[offset].m_key_image_known && !m_transfers[offset].m_key_image_request))
|
||||
++offset;
|
||||
|
||||
outs.reserve(m_transfers.size() - offset);
|
||||
|
@ -11389,7 +11466,7 @@ size_t wallet2::import_outputs(const std::pair<size_t, std::vector<tools::wallet
|
|||
const size_t original_size = m_transfers.size();
|
||||
m_transfers.resize(offset + outputs.second.size());
|
||||
for (size_t i = 0; i < offset; ++i)
|
||||
m_transfers[i].m_key_image_requested = false;
|
||||
m_transfers[i].m_key_image_request = false;
|
||||
for (size_t i = 0; i < outputs.second.size(); ++i)
|
||||
{
|
||||
transfer_details td = outputs.second[i];
|
||||
|
@ -11430,7 +11507,7 @@ process:
|
|||
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
|
||||
expand_subaddresses(td.m_subaddr_index);
|
||||
td.m_key_image_known = true;
|
||||
td.m_key_image_requested = true;
|
||||
td.m_key_image_request = true;
|
||||
td.m_key_image_partial = false;
|
||||
THROW_WALLET_EXCEPTION_IF(in_ephemeral.pub != out_key,
|
||||
error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key at index " + boost::lexical_cast<std::string>(i + offset));
|
||||
|
@ -11676,7 +11753,7 @@ void wallet2::update_multisig_rescan_info(const std::vector<std::vector<rct::key
|
|||
m_key_images.erase(td.m_key_image);
|
||||
td.m_key_image = get_multisig_composite_key_image(n);
|
||||
td.m_key_image_known = true;
|
||||
td.m_key_image_requested = false;
|
||||
td.m_key_image_request = false;
|
||||
td.m_key_image_partial = false;
|
||||
td.m_multisig_k = multisig_k[n];
|
||||
m_key_images[td.m_key_image] = n;
|
||||
|
|
|
@ -267,7 +267,7 @@ namespace tools
|
|||
uint64_t m_amount;
|
||||
bool m_rct;
|
||||
bool m_key_image_known;
|
||||
bool m_key_image_requested;
|
||||
bool m_key_image_request; // view wallets: we want to request it; cold wallets: it was requested
|
||||
size_t m_pk_index;
|
||||
cryptonote::subaddress_index m_subaddr_index;
|
||||
bool m_key_image_partial;
|
||||
|
@ -292,7 +292,7 @@ namespace tools
|
|||
FIELD(m_amount)
|
||||
FIELD(m_rct)
|
||||
FIELD(m_key_image_known)
|
||||
FIELD(m_key_image_requested)
|
||||
FIELD(m_key_image_request)
|
||||
FIELD(m_pk_index)
|
||||
FIELD(m_subaddr_index)
|
||||
FIELD(m_key_image_partial)
|
||||
|
@ -448,6 +448,7 @@ namespace tools
|
|||
{
|
||||
std::vector<pending_tx> ptx;
|
||||
std::vector<crypto::key_image> key_images;
|
||||
std::unordered_map<crypto::public_key, crypto::key_image> tx_key_images;
|
||||
};
|
||||
|
||||
struct multisig_tx_set
|
||||
|
@ -927,6 +928,9 @@ namespace tools
|
|||
if(ver < 27)
|
||||
return;
|
||||
a & m_device_last_key_image_sync;
|
||||
if(ver < 28)
|
||||
return;
|
||||
a & m_cold_key_images;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -1358,6 +1362,7 @@ namespace tools
|
|||
uint64_t m_upper_transaction_weight_limit; //TODO: auto-calc this value or request from daemon, now use some fixed value
|
||||
const std::vector<std::vector<tools::wallet2::multisig_info>> *m_multisig_rescan_info;
|
||||
const std::vector<std::vector<rct::key>> *m_multisig_rescan_k;
|
||||
std::unordered_map<crypto::public_key, crypto::key_image> m_cold_key_images;
|
||||
|
||||
std::atomic<bool> m_run;
|
||||
|
||||
|
@ -1452,7 +1457,7 @@ namespace tools
|
|||
std::unique_ptr<wallet_device_callback> m_device_callback;
|
||||
};
|
||||
}
|
||||
BOOST_CLASS_VERSION(tools::wallet2, 27)
|
||||
BOOST_CLASS_VERSION(tools::wallet2, 28)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 11)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::multisig_info, 1)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0)
|
||||
|
@ -1464,7 +1469,7 @@ BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 6)
|
|||
BOOST_CLASS_VERSION(tools::wallet2::address_book_row, 17)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::reserve_proof_entry, 0)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::unsigned_tx_set, 0)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::signed_tx_set, 0)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::signed_tx_set, 1)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::tx_construction_data, 3)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::pending_tx, 3)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::multisig_sig, 0)
|
||||
|
@ -1513,7 +1518,7 @@ namespace boost
|
|||
}
|
||||
if (ver < 10)
|
||||
{
|
||||
x.m_key_image_requested = false;
|
||||
x.m_key_image_request = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1601,7 +1606,7 @@ namespace boost
|
|||
initialize_transfer_details(a, x, ver);
|
||||
return;
|
||||
}
|
||||
a & x.m_key_image_requested;
|
||||
a & x.m_key_image_request;
|
||||
if (ver < 11)
|
||||
return;
|
||||
a & x.m_uses;
|
||||
|
@ -1801,6 +1806,9 @@ namespace boost
|
|||
{
|
||||
a & x.ptx;
|
||||
a & x.key_images;
|
||||
if (ver < 1)
|
||||
return;
|
||||
a & x.tx_key_images;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
|
|
Loading…
Reference in a new issue