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:
parent
dbf2ab56c5
commit
7abfc5474c
2 changed files with 52 additions and 7 deletions
|
@ -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);
|
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>> wallet2::export_key_images() const
|
||||||
{
|
{
|
||||||
std::vector<std::pair<crypto::key_image, crypto::signature>> ski;
|
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
|
// 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,
|
crypto::public_key tx_pub_key = get_tx_pub_key_from_received_outs(td);
|
||||||
"Public key wasn't found in the transaction extra");
|
|
||||||
crypto::public_key tx_pub_key = pub_key_field.pub_key;
|
|
||||||
|
|
||||||
// generate ephemeral secret key
|
// generate ephemeral secret key
|
||||||
crypto::key_image ki;
|
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(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,
|
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));
|
"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,
|
crypto::public_key tx_pub_key = get_tx_pub_key_from_received_outs(td);
|
||||||
"Public key wasn't found in the transaction extra at index " + boost::lexical_cast<std::string>(i));
|
|
||||||
|
|
||||||
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;
|
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,
|
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));
|
error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key at index " + boost::lexical_cast<std::string>(i));
|
||||||
|
|
|
@ -591,6 +591,7 @@ namespace tools
|
||||||
template<typename entry>
|
template<typename entry>
|
||||||
void get_outs(std::vector<std::vector<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;
|
||||||
|
|
||||||
cryptonote::account_base m_account;
|
cryptonote::account_base m_account;
|
||||||
std::string m_daemon_address;
|
std::string m_daemon_address;
|
||||||
|
|
Loading…
Reference in a new issue