aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormoneromooo-monero <moneromooo-monero@users.noreply.github.com>2016-11-19 09:36:40 +0000
committermoneromooo-monero <moneromooo-monero@users.noreply.github.com>2016-11-19 09:36:40 +0000
commit7abfc5474c0f86e16c405f154570310468b635c2 (patch)
treedc6feb3397b6e0f1b498388ce45588fe87e476ae /src
parentMerge pull request #1346 (diff)
downloadmonero-7abfc5474c0f86e16c405f154570310468b635c2.tar.xz
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.
Diffstat (limited to 'src')
-rw-r--r--src/wallet/wallet2.cpp58
-rw-r--r--src/wallet/wallet2.h1
2 files changed, 52 insertions, 7 deletions
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 15a134257..13743d46b 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -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));
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 6168873d5..23a39a85b 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -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;