From f4a3ce15c196c2e8c723ab459be69e60d7de6007 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Fri, 9 Dec 2016 18:21:21 +0000 Subject: [PATCH] Fix sending outputs from a tx with more than one pubkey A bug in cold signing caused a spurious pubkey to be included in transactions, so we need to ensure we use the correct one when sending outputs from one of those. --- .../cryptonote_format_utils.cpp | 18 +++++++++++------- src/cryptonote_core/cryptonote_format_utils.h | 6 +++--- src/wallet/wallet2.cpp | 9 +++++++-- src/wallet/wallet2.h | 14 +++++++++++++- 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index 394a43831..d6dbc400a 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -320,26 +320,26 @@ namespace cryptonote return true; } //--------------------------------------------------------------- - crypto::public_key get_tx_pub_key_from_extra(const std::vector& tx_extra) + crypto::public_key get_tx_pub_key_from_extra(const std::vector& tx_extra, size_t pk_index) { std::vector tx_extra_fields; parse_tx_extra(tx_extra, tx_extra_fields); tx_extra_pub_key pub_key_field; - if(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field)) + if(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, pk_index)) return null_pkey; return pub_key_field.pub_key; } //--------------------------------------------------------------- - crypto::public_key get_tx_pub_key_from_extra(const transaction_prefix& tx_prefix) + crypto::public_key get_tx_pub_key_from_extra(const transaction_prefix& tx_prefix, size_t pk_index) { - return get_tx_pub_key_from_extra(tx_prefix.extra); + return get_tx_pub_key_from_extra(tx_prefix.extra, pk_index); } //--------------------------------------------------------------- - crypto::public_key get_tx_pub_key_from_extra(const transaction& tx) + crypto::public_key get_tx_pub_key_from_extra(const transaction& tx, size_t pk_index) { - return get_tx_pub_key_from_extra(tx.extra); + return get_tx_pub_key_from_extra(tx.extra, pk_index); } //--------------------------------------------------------------- bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key) @@ -534,8 +534,10 @@ namespace cryptonote uint64_t summary_inputs_money = 0; //fill inputs + int idx = -1; BOOST_FOREACH(const tx_source_entry& src_entr, sources) { + ++idx; if(src_entr.real_output >= src_entr.outputs.size()) { LOG_ERROR("real_output index (" << src_entr.real_output << ")bigger than output_keys.size()=" << src_entr.outputs.size()); @@ -553,9 +555,11 @@ namespace cryptonote //check that derivated key is equal with real output key if( !(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].second.dest) ) { - LOG_ERROR("derived public key mismatch with output public key! "<< ENDL << "derived_key:" + LOG_ERROR("derived public key mismatch with output public key at index " << idx << ", real out " << src_entr.real_output << "! "<< ENDL << "derived_key:" << string_tools::pod_to_hex(in_ephemeral.pub) << ENDL << "real output_public_key:" << string_tools::pod_to_hex(src_entr.outputs[src_entr.real_output].second) ); + LOG_ERROR("amount " << src_entr.amount << ", rct " << src_entr.rct); + LOG_ERROR("tx pubkey " << src_entr.real_out_tx_key << ", real_output_in_tx_index " << src_entr.real_output_in_tx_index); return false; } diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h index 9f9ed8625..704b8467d 100644 --- a/src/cryptonote_core/cryptonote_format_utils.h +++ b/src/cryptonote_core/cryptonote_format_utils.h @@ -104,9 +104,9 @@ namespace cryptonote } bool parse_tx_extra(const std::vector& tx_extra, std::vector& tx_extra_fields); - crypto::public_key get_tx_pub_key_from_extra(const std::vector& tx_extra); - crypto::public_key get_tx_pub_key_from_extra(const transaction_prefix& tx); - crypto::public_key get_tx_pub_key_from_extra(const transaction& tx); + crypto::public_key get_tx_pub_key_from_extra(const std::vector& tx_extra, size_t pk_index = 0); + crypto::public_key get_tx_pub_key_from_extra(const transaction_prefix& tx, size_t pk_index = 0); + crypto::public_key get_tx_pub_key_from_extra(const transaction& tx, size_t pk_index = 0); bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key); bool add_extra_nonce_to_tx_extra(std::vector& tx_extra, const blobdata& extra_nonce); bool remove_field_from_tx_extra(std::vector& tx_extra, const std::type_info &type); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 2d293d45c..fee1a0ab7 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -846,6 +846,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s td.m_key_image = ki[o]; td.m_key_image_known = !m_watch_only; td.m_amount = tx.vout[o].amount; + td.m_pk_index = pk_index - 1; if (td.m_amount == 0) { td.m_mask = mask[o]; @@ -894,6 +895,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s td.m_tx = (const cryptonote::transaction_prefix&)tx; td.m_txid = txid(); td.m_amount = tx.vout[o].amount; + td.m_pk_index = pk_index - 1; if (td.m_amount == 0) { td.m_mask = mask[o]; @@ -3623,7 +3625,7 @@ void wallet2::transfer_selected(const std::vector(td.m_tx.vout[td.m_internal_output_index].target).key); real_oe.second.mask = rct::commit(td.amount(), td.m_mask); *it_to_replace = real_oe; - src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_tx); + src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_tx, td.m_pk_index); src.real_output = it_to_replace - src.outputs.begin(); src.real_output_in_tx_index = td.m_internal_output_index; detail::print_source_entry(src); @@ -3699,6 +3701,9 @@ void wallet2::transfer_selected_rct(std::vector(td.m_tx.vout[td.m_internal_output_index].target).key); real_oe.second.mask = rct::commit(td.amount(), td.m_mask); *it_to_replace = real_oe; - src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_tx); + src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_tx, td.m_pk_index); src.real_output = it_to_replace - src.outputs.begin(); src.real_output_in_tx_index = td.m_internal_output_index; src.mask = td.m_mask; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index dcb6367d1..616b74edb 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -129,6 +129,7 @@ namespace tools uint64_t m_amount; bool m_rct; bool m_key_image_known; + size_t m_pk_index; bool is_rct() const { return m_rct; } uint64_t amount() const { return m_amount; } @@ -147,6 +148,7 @@ namespace tools FIELD(m_amount) FIELD(m_rct) FIELD(m_key_image_known) + FIELD(m_pk_index) END_SERIALIZE() }; @@ -644,7 +646,7 @@ namespace tools }; } BOOST_CLASS_VERSION(tools::wallet2, 15) -BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 6) +BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 7) BOOST_CLASS_VERSION(tools::wallet2::payment_details, 1) BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 6) BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 3) @@ -677,6 +679,10 @@ namespace boost { x.m_key_image_known = true; } + if (ver < 7) + { + x.m_pk_index = 0; + } } template @@ -738,6 +744,12 @@ namespace boost return; } a & x.m_key_image_known; + if (ver < 7) + { + initialize_transfer_details(a, x, ver); + return; + } + a & x.m_pk_index; } template