mirror of
https://github.com/monero-project/monero.git
synced 2024-11-18 00:37:43 +00:00
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.
This commit is contained in:
parent
45bb393577
commit
f4a3ce15c1
4 changed files with 34 additions and 13 deletions
|
@ -320,26 +320,26 @@ namespace cryptonote
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra)
|
crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra, size_t pk_index)
|
||||||
{
|
{
|
||||||
std::vector<tx_extra_field> tx_extra_fields;
|
std::vector<tx_extra_field> tx_extra_fields;
|
||||||
parse_tx_extra(tx_extra, tx_extra_fields);
|
parse_tx_extra(tx_extra, tx_extra_fields);
|
||||||
|
|
||||||
tx_extra_pub_key pub_key_field;
|
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 null_pkey;
|
||||||
|
|
||||||
return pub_key_field.pub_key;
|
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)
|
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;
|
uint64_t summary_inputs_money = 0;
|
||||||
//fill inputs
|
//fill inputs
|
||||||
|
int idx = -1;
|
||||||
BOOST_FOREACH(const tx_source_entry& src_entr, sources)
|
BOOST_FOREACH(const tx_source_entry& src_entr, sources)
|
||||||
{
|
{
|
||||||
|
++idx;
|
||||||
if(src_entr.real_output >= src_entr.outputs.size())
|
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());
|
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
|
//check that derivated key is equal with real output key
|
||||||
if( !(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].second.dest) )
|
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(in_ephemeral.pub) << ENDL << "real output_public_key:"
|
||||||
<< string_tools::pod_to_hex(src_entr.outputs[src_entr.real_output].second) );
|
<< 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,9 +104,9 @@ namespace cryptonote
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<tx_extra_field>& tx_extra_fields);
|
bool parse_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<tx_extra_field>& tx_extra_fields);
|
||||||
crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra);
|
crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra, size_t pk_index = 0);
|
||||||
crypto::public_key get_tx_pub_key_from_extra(const transaction_prefix& tx);
|
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);
|
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_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key);
|
||||||
bool add_extra_nonce_to_tx_extra(std::vector<uint8_t>& tx_extra, const blobdata& extra_nonce);
|
bool add_extra_nonce_to_tx_extra(std::vector<uint8_t>& tx_extra, const blobdata& extra_nonce);
|
||||||
bool remove_field_from_tx_extra(std::vector<uint8_t>& tx_extra, const std::type_info &type);
|
bool remove_field_from_tx_extra(std::vector<uint8_t>& tx_extra, const std::type_info &type);
|
||||||
|
|
|
@ -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 = ki[o];
|
||||||
td.m_key_image_known = !m_watch_only;
|
td.m_key_image_known = !m_watch_only;
|
||||||
td.m_amount = tx.vout[o].amount;
|
td.m_amount = tx.vout[o].amount;
|
||||||
|
td.m_pk_index = pk_index - 1;
|
||||||
if (td.m_amount == 0)
|
if (td.m_amount == 0)
|
||||||
{
|
{
|
||||||
td.m_mask = mask[o];
|
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_tx = (const cryptonote::transaction_prefix&)tx;
|
||||||
td.m_txid = txid();
|
td.m_txid = txid();
|
||||||
td.m_amount = tx.vout[o].amount;
|
td.m_amount = tx.vout[o].amount;
|
||||||
|
td.m_pk_index = pk_index - 1;
|
||||||
if (td.m_amount == 0)
|
if (td.m_amount == 0)
|
||||||
{
|
{
|
||||||
td.m_mask = mask[o];
|
td.m_mask = mask[o];
|
||||||
|
@ -3623,7 +3625,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
|
||||||
real_oe.second.dest = rct::pk2rct(boost::get<txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key);
|
real_oe.second.dest = rct::pk2rct(boost::get<txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key);
|
||||||
real_oe.second.mask = rct::commit(td.amount(), td.m_mask);
|
real_oe.second.mask = rct::commit(td.amount(), td.m_mask);
|
||||||
*it_to_replace = real_oe;
|
*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 = it_to_replace - src.outputs.begin();
|
||||||
src.real_output_in_tx_index = td.m_internal_output_index;
|
src.real_output_in_tx_index = td.m_internal_output_index;
|
||||||
detail::print_source_entry(src);
|
detail::print_source_entry(src);
|
||||||
|
@ -3699,6 +3701,9 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
|
||||||
uint64_t upper_transaction_size_limit = get_upper_tranaction_size_limit();
|
uint64_t upper_transaction_size_limit = get_upper_tranaction_size_limit();
|
||||||
uint64_t needed_money = fee;
|
uint64_t needed_money = fee;
|
||||||
LOG_PRINT_L2("transfer: starting with fee " << print_money (needed_money));
|
LOG_PRINT_L2("transfer: starting with fee " << print_money (needed_money));
|
||||||
|
LOG_PRINT_L0("selected transfers: ");
|
||||||
|
for (auto t: selected_transfers)
|
||||||
|
LOG_PRINT_L2(" " << t);
|
||||||
|
|
||||||
// calculate total amount being sent to all destinations
|
// calculate total amount being sent to all destinations
|
||||||
// throw if total amount overflows uint64_t
|
// throw if total amount overflows uint64_t
|
||||||
|
@ -3759,7 +3764,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
|
||||||
real_oe.second.dest = rct::pk2rct(boost::get<txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key);
|
real_oe.second.dest = rct::pk2rct(boost::get<txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key);
|
||||||
real_oe.second.mask = rct::commit(td.amount(), td.m_mask);
|
real_oe.second.mask = rct::commit(td.amount(), td.m_mask);
|
||||||
*it_to_replace = real_oe;
|
*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 = it_to_replace - src.outputs.begin();
|
||||||
src.real_output_in_tx_index = td.m_internal_output_index;
|
src.real_output_in_tx_index = td.m_internal_output_index;
|
||||||
src.mask = td.m_mask;
|
src.mask = td.m_mask;
|
||||||
|
|
|
@ -129,6 +129,7 @@ namespace tools
|
||||||
uint64_t m_amount;
|
uint64_t m_amount;
|
||||||
bool m_rct;
|
bool m_rct;
|
||||||
bool m_key_image_known;
|
bool m_key_image_known;
|
||||||
|
size_t m_pk_index;
|
||||||
|
|
||||||
bool is_rct() const { return m_rct; }
|
bool is_rct() const { return m_rct; }
|
||||||
uint64_t amount() const { return m_amount; }
|
uint64_t amount() const { return m_amount; }
|
||||||
|
@ -147,6 +148,7 @@ namespace tools
|
||||||
FIELD(m_amount)
|
FIELD(m_amount)
|
||||||
FIELD(m_rct)
|
FIELD(m_rct)
|
||||||
FIELD(m_key_image_known)
|
FIELD(m_key_image_known)
|
||||||
|
FIELD(m_pk_index)
|
||||||
END_SERIALIZE()
|
END_SERIALIZE()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -644,7 +646,7 @@ namespace tools
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
BOOST_CLASS_VERSION(tools::wallet2, 15)
|
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::payment_details, 1)
|
||||||
BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 6)
|
BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 6)
|
||||||
BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 3)
|
BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 3)
|
||||||
|
@ -677,6 +679,10 @@ namespace boost
|
||||||
{
|
{
|
||||||
x.m_key_image_known = true;
|
x.m_key_image_known = true;
|
||||||
}
|
}
|
||||||
|
if (ver < 7)
|
||||||
|
{
|
||||||
|
x.m_pk_index = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
|
@ -738,6 +744,12 @@ namespace boost
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
a & x.m_key_image_known;
|
a & x.m_key_image_known;
|
||||||
|
if (ver < 7)
|
||||||
|
{
|
||||||
|
initialize_transfer_details(a, x, ver);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
a & x.m_pk_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
|
|
Loading…
Reference in a new issue