wallet: fix exporting outputs and key images with txes with two pubkeys

This also needs to make sure to pick the correct one, in the case
where cold signing caused to tx keys to be included.
This commit is contained in:
moneromooo-monero 2016-11-19 09:36:40 +00:00
parent dbf2ab56c5
commit 7abfc5474c
No known key found for this signature in database
GPG Key ID: 686F07454D6CEFC3
2 changed files with 52 additions and 7 deletions

View File

@ -4688,6 +4688,53 @@ bool wallet2::verify(const std::string &data, const cryptonote::account_public_a
return crypto::check_signature(hash, address.m_spend_public_key, s);
}
//----------------------------------------------------------------------------------------------------
crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const
{
std::vector<tx_extra_field> tx_extra_fields;
if(!parse_tx_extra(td.m_tx.extra, tx_extra_fields))
{
// Extra may only be partially parsed, it's OK if tx_extra_fields contains public key
}
// Due to a previous bug, there might be more than one tx pubkey in extra, one being
// the result of a previously discarded signature.
// For speed, since scanning for outputs is a slow process, we check whether extra
// contains more than one pubkey. If not, the first one is returned. If yes, they're
// checked for whether they yield at least one output
tx_extra_pub_key pub_key_field;
THROW_WALLET_EXCEPTION_IF(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, 0), error::wallet_internal_error,
"Public key wasn't found in the transaction extra");
const crypto::public_key tx_pub_key = pub_key_field.pub_key;
bool two_found = find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, 1);
if (!two_found) {
// easy case, just one found
return tx_pub_key;
}
// more than one, loop and search
const cryptonote::account_keys& keys = m_account.get_keys();
size_t pk_index = 0;
while (find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, pk_index++)) {
const crypto::public_key tx_pub_key = pub_key_field.pub_key;
crypto::key_derivation derivation;
generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation);
for (size_t i = 0; i < td.m_tx.vout.size(); ++i)
{
uint64_t money_transfered = 0;
bool error = false, received = false;
check_acc_out_precomp(keys.m_account_address.m_spend_public_key, td.m_tx.vout[i], derivation, i, received, money_transfered, error);
if (!error && received)
return tx_pub_key;
}
}
// we found no key yielding an output
THROW_WALLET_EXCEPTION_IF(true, error::wallet_internal_error,
"Public key yielding at least one output wasn't found in the transaction extra");
return cryptonote::null_pkey;
}
//----------------------------------------------------------------------------------------------------
std::vector<std::pair<crypto::key_image, crypto::signature>> wallet2::export_key_images() const
{
std::vector<std::pair<crypto::key_image, crypto::signature>> ski;
@ -4713,10 +4760,8 @@ std::vector<std::pair<crypto::key_image, crypto::signature>> wallet2::export_key
{
// Extra may only be partially parsed, it's OK if tx_extra_fields contains public key
}
tx_extra_pub_key pub_key_field;
THROW_WALLET_EXCEPTION_IF(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field), error::wallet_internal_error,
"Public key wasn't found in the transaction extra");
crypto::public_key tx_pub_key = pub_key_field.pub_key;
crypto::public_key tx_pub_key = get_tx_pub_key_from_received_outs(td);
// generate ephemeral secret key
crypto::key_image ki;
@ -4845,10 +4890,9 @@ size_t wallet2::import_outputs(const std::vector<tools::wallet2::transfer_detail
THROW_WALLET_EXCEPTION_IF(td.m_tx.vout.empty(), error::wallet_internal_error, "tx with no outputs at index " + boost::lexical_cast<std::string>(i));
THROW_WALLET_EXCEPTION_IF(!parse_tx_extra(td.m_tx.extra, tx_extra_fields), error::wallet_internal_error,
"Transaction extra has unsupported format at index " + boost::lexical_cast<std::string>(i));
THROW_WALLET_EXCEPTION_IF(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field), error::wallet_internal_error,
"Public key wasn't found in the transaction extra at index " + boost::lexical_cast<std::string>(i));
crypto::public_key tx_pub_key = get_tx_pub_key_from_received_outs(td);
cryptonote::generate_key_image_helper(m_account.get_keys(), pub_key_field.pub_key, td.m_internal_output_index, in_ephemeral, td.m_key_image);
cryptonote::generate_key_image_helper(m_account.get_keys(), tx_pub_key, td.m_internal_output_index, in_ephemeral, td.m_key_image);
td.m_key_image_known = true;
THROW_WALLET_EXCEPTION_IF(in_ephemeral.pub != boost::get<cryptonote::txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key,
error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key at index " + boost::lexical_cast<std::string>(i));

View File

@ -591,6 +591,7 @@ namespace tools
template<typename entry>
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);
crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const;
cryptonote::account_base m_account;
std::string m_daemon_address;