diff --git a/src/cryptonote_core/cryptonote_basic.h b/src/cryptonote_core/cryptonote_basic.h index afe785eb..e5a5cc6f 100644 --- a/src/cryptonote_core/cryptonote_basic.h +++ b/src/cryptonote_core/cryptonote_basic.h @@ -180,7 +180,7 @@ namespace cryptonote FIELD(extra) END_SERIALIZE() - protected: + public: transaction_prefix(){} }; diff --git a/src/cryptonote_core/cryptonote_boost_serialization.h b/src/cryptonote_core/cryptonote_boost_serialization.h index f222db94..41f86480 100644 --- a/src/cryptonote_core/cryptonote_boost_serialization.h +++ b/src/cryptonote_core/cryptonote_boost_serialization.h @@ -143,6 +143,16 @@ namespace boost } + template + inline void serialize(Archive &a, cryptonote::transaction_prefix &x, const boost::serialization::version_type ver) + { + a & x.version; + a & x.unlock_time; + a & x.vin; + a & x.vout; + a & x.extra; + } + template inline void serialize(Archive &a, cryptonote::transaction &x, const boost::serialization::version_type ver) { diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index ee9a0080..ddcab4f0 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -321,6 +321,11 @@ namespace cryptonote return pub_key_field.pub_key; } //--------------------------------------------------------------- + crypto::public_key get_tx_pub_key_from_extra(const transaction_prefix& tx_prefix) + { + return get_tx_pub_key_from_extra(tx_prefix.extra); + } + //--------------------------------------------------------------- crypto::public_key get_tx_pub_key_from_extra(const transaction& tx) { return get_tx_pub_key_from_extra(tx.extra); diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h index 6dac8e88..e0ffbed6 100644 --- a/src/cryptonote_core/cryptonote_format_utils.h +++ b/src/cryptonote_core/cryptonote_format_utils.h @@ -89,6 +89,7 @@ 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); 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); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 35469226..9e734145 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -2068,7 +2068,7 @@ bool simple_wallet::show_incoming_transfers(const std::vector& args (m_wallet->is_transfer_unlocked(td) ? tr("unlocked") : tr("locked")) % (td.is_rct() ? tr("RingCT") : tr("-")) % td.m_global_output_index % - get_transaction_hash (td.m_tx); + td.m_txid; } } diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp index db42e214..95aafb04 100644 --- a/src/wallet/api/transaction_history.cpp +++ b/src/wallet/api/transaction_history.cpp @@ -165,9 +165,8 @@ void TransactionHistoryImpl::refresh() for (std::list>::const_iterator i = upayments.begin(); i != upayments.end(); ++i) { const tools::wallet2::unconfirmed_transfer_details &pd = i->second; const crypto::hash &hash = i->first; - uint64_t amount = 0; - cryptonote::get_inputs_money_amount(pd.m_tx, amount); - uint64_t fee = amount - get_outs_money_amount(pd.m_tx); + uint64_t amount = pd.m_amount_in; + uint64_t fee = amount - pd.m_amount_out; std::string payment_id = string_tools::pod_to_hex(i->second.m_payment_id); if (payment_id.substr(16).find_first_not_of('0') == std::string::npos) payment_id = payment_id.substr(0,16); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 4e014462..5d51efc1 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -225,6 +225,24 @@ static uint64_t decodeRct(const rct::rctSig & rv, const rct::key & sk, unsigned //---------------------------------------------------------------------------------------------------- void wallet2::process_new_transaction(const cryptonote::transaction& tx, const std::vector &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool) { + class lazy_txid_getter + { + const cryptonote::transaction &tx; + crypto::hash lazy_txid; + bool computed; + public: + lazy_txid_getter(const transaction &tx): tx(tx), computed(false) {} + const crypto::hash &operator()() + { + if (!computed) + { + lazy_txid = cryptonote::get_transaction_hash(tx); + computed = true; + } + return lazy_txid; + } + } txid(tx); + if (!miner_tx) process_unconfirmed(tx, height); std::vector outs; @@ -235,7 +253,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s if(!parse_tx_extra(tx.extra, tx_extra_fields)) { // Extra may only be partially parsed, it's OK if tx_extra_fields contains public key - LOG_PRINT_L0("Transaction extra has unsupported format: " << get_transaction_hash(tx)); + LOG_PRINT_L0("Transaction extra has unsupported format: " << txid()); } // Don't try to extract tx public key if tx has no ouputs @@ -244,7 +262,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s tx_extra_pub_key pub_key_field; if(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field)) { - LOG_PRINT_L0("Public key wasn't found in the transaction extra. Skipping transaction " << get_transaction_hash(tx)); + LOG_PRINT_L0("Public key wasn't found in the transaction extra. Skipping transaction " << txid()); if(0 != m_callback) m_callback->on_skip_transaction(height, tx); return; @@ -452,7 +470,8 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s td.m_block_height = height; td.m_internal_output_index = o; td.m_global_output_index = o_indices[o]; - td.m_tx = tx; + td.m_tx = (const cryptonote::transaction_prefix&)tx; + td.m_txid = txid(); td.m_key_image = ki[o]; td.m_amount = tx.vout[o].amount; if (td.m_amount == 0) @@ -466,9 +485,9 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s } set_unspent(td); m_key_images[td.m_key_image] = m_transfers.size()-1; - LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << get_transaction_hash(tx)); + LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid()); if (0 != m_callback) - m_callback->on_money_received(height, td.m_tx, td.m_amount); + m_callback->on_money_received(height, tx, td.m_amount); } } else if (m_transfers[kit->second].m_spent || m_transfers[kit->second].amount() >= tx.vout[o].amount) @@ -492,7 +511,8 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s td.m_block_height = height; td.m_internal_output_index = o; td.m_global_output_index = o_indices[o]; - td.m_tx = tx; + td.m_tx = (const cryptonote::transaction_prefix&)tx; + td.m_txid = txid(); td.m_amount = tx.vout[o].amount; if (td.m_amount == 0) { @@ -506,9 +526,9 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s THROW_WALLET_EXCEPTION_IF(td.m_key_image != ki[o], error::wallet_internal_error, "Inconsistent key images"); THROW_WALLET_EXCEPTION_IF(td.m_spent, error::wallet_internal_error, "Inconsistent spent status"); - LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << get_transaction_hash(tx)); + LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid()); if (0 != m_callback) - m_callback->on_money_received(height, td.m_tx, td.m_amount); + m_callback->on_money_received(height, tx, td.m_amount); } } } @@ -533,11 +553,11 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s std::string(", expected ") + print_money(td.amount())); } amount = td.amount(); - LOG_PRINT_L0("Spent money: " << print_money(amount) << ", with tx: " << get_transaction_hash(tx)); + LOG_PRINT_L0("Spent money: " << print_money(amount) << ", with tx: " << txid()); tx_money_spent_in_ins += amount; set_spent(td, height); if (0 != m_callback) - m_callback->on_money_spent(height, td.m_tx, amount, tx); + m_callback->on_money_spent(height, tx, amount, tx); } } @@ -589,7 +609,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s } payment_details payment; - payment.m_tx_hash = cryptonote::get_transaction_hash(tx); + payment.m_tx_hash = txid(); payment.m_amount = received; payment.m_block_height = height; payment.m_unlock_time = tx.unlock_time; @@ -604,6 +624,9 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s //---------------------------------------------------------------------------------------------------- void wallet2::process_unconfirmed(const cryptonote::transaction& tx, uint64_t height) { + if (m_unconfirmed_txs.empty()) + return; + crypto::hash txid = get_transaction_hash(tx); auto unconf_it = m_unconfirmed_txs.find(txid); if(unconf_it != m_unconfirmed_txs.end()) { @@ -915,7 +938,7 @@ void wallet2::update_pool_state() std::unordered_map::iterator it = m_unconfirmed_txs.begin(); while (it != m_unconfirmed_txs.end()) { - const std::string txid = epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(it->second.m_tx)); + const std::string txid = epee::string_tools::pod_to_hex(it->first); bool found = false; for (auto it2: res.transactions) { @@ -1141,7 +1164,7 @@ void wallet2::refresh(uint64_t start_height, uint64_t & blocks_fetched, bool& re blocks_fetched = 0; uint64_t added_blocks = 0; size_t try_count = 0; - crypto::hash last_tx_hash_id = m_transfers.size() ? get_transaction_hash(m_transfers.back().m_tx) : null_hash; + crypto::hash last_tx_hash_id = m_transfers.size() ? m_transfers.back().m_txid : null_hash; std::list short_chain_history; boost::thread pull_thread; uint64_t blocks_start_height; @@ -1213,7 +1236,7 @@ void wallet2::refresh(uint64_t start_height, uint64_t & blocks_fetched, bool& re } } } - if(last_tx_hash_id != (m_transfers.size() ? get_transaction_hash(m_transfers.back().m_tx) : null_hash)) + if(last_tx_hash_id != (m_transfers.size() ? m_transfers.back().m_txid : null_hash)) received_money = true; try @@ -2179,11 +2202,9 @@ float wallet2::get_output_relatedness(const transfer_details &td0, const transfe { int dh; -#if 0 // expensive test, and same tx will fall onto the same block height below - if (get_transaction_hash(td0.m_tx) == get_transaction_hash(td1.m_tx)) + if (td0.m_txid == td1.m_txid) return 1.0f; -#endif // same block height -> possibly tx burst, or same tx (since above is disabled) dh = td0.m_block_height > td1.m_block_height ? td0.m_block_height - td1.m_block_height : td1.m_block_height - td0.m_block_height; @@ -2269,7 +2290,7 @@ void wallet2::add_unconfirmed_tx(const cryptonote::transaction& tx, uint64_t amo utd.m_amount_out += d.amount; utd.m_change = change_amount; utd.m_sent_time = time(NULL); - utd.m_tx = tx; + utd.m_tx = (const cryptonote::transaction_prefix&)tx; utd.m_dests = dests; utd.m_payment_id = payment_id; utd.m_state = wallet2::unconfirmed_transfer_details::pending; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 4c361df8..488902d5 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -99,7 +99,8 @@ namespace tools struct transfer_details { uint64_t m_block_height; - cryptonote::transaction m_tx; + cryptonote::transaction_prefix m_tx; + crypto::hash m_txid; size_t m_internal_output_index; uint64_t m_global_output_index; bool m_spent; @@ -123,7 +124,7 @@ namespace tools struct unconfirmed_transfer_details { - cryptonote::transaction m_tx; + cryptonote::transaction_prefix m_tx; uint64_t m_amount_in; uint64_t m_amount_out; uint64_t m_change; @@ -502,9 +503,9 @@ namespace tools }; } BOOST_CLASS_VERSION(tools::wallet2, 14) -BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 2) +BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 3) BOOST_CLASS_VERSION(tools::wallet2::payment_details, 1) -BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 4) +BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 5) BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 2) namespace boost @@ -535,7 +536,17 @@ namespace boost a & x.m_block_height; a & x.m_global_output_index; a & x.m_internal_output_index; - a & x.m_tx; + if (ver < 3) + { + cryptonote::transaction tx; + a & tx; + x.m_tx = (const cryptonote::transaction_prefix&)tx; + x.m_txid = cryptonote::get_transaction_hash(tx); + } + else + { + a & x.m_tx; + } a & x.m_spent; a & x.m_key_image; if (ver < 1) @@ -552,6 +563,9 @@ namespace boost return; } a & x.m_spent_height; + if (ver < 3) + return; + a & x.m_txid; } template @@ -559,7 +573,16 @@ namespace boost { a & x.m_change; a & x.m_sent_time; - a & x.m_tx; + if (ver < 5) + { + cryptonote::transaction tx; + a & tx; + x.m_tx = (const cryptonote::transaction_prefix&)tx; + } + else + { + a & x.m_tx; + } if (ver < 1) return; a & x.m_dests; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 20a9ebe9..1786b776 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -729,7 +729,7 @@ namespace tools rpc_transfers.amount = td.amount(); rpc_transfers.spent = td.m_spent; rpc_transfers.global_index = td.m_global_output_index; - rpc_transfers.tx_hash = epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(td.m_tx)); + rpc_transfers.tx_hash = epee::string_tools::pod_to_hex(td.m_txid); rpc_transfers.tx_size = txBlob.size(); res.transfers.push_back(rpc_transfers); } diff --git a/tests/functional_tests/transactions_flow_test.cpp b/tests/functional_tests/transactions_flow_test.cpp index 6bf91010..58532834 100644 --- a/tests/functional_tests/transactions_flow_test.cpp +++ b/tests/functional_tests/transactions_flow_test.cpp @@ -281,7 +281,7 @@ bool transactions_flow_test(std::string& working_folder, w2.get_transfers(tc); BOOST_FOREACH(tools::wallet2::transfer_details& td, tc) { - auto it = txs.find(get_transaction_hash(td.m_tx)); + auto it = txs.find(td.m_txid); CHECK_AND_ASSERT_MES(it != txs.end(), false, "transaction not found in local cache"); it->second.m_received_count += 1; } diff --git a/tests/unit_tests/output_selection.cpp b/tests/unit_tests/output_selection.cpp index a3164fa4..4344d1ff 100644 --- a/tests/unit_tests/output_selection.cpp +++ b/tests/unit_tests/output_selection.cpp @@ -42,6 +42,11 @@ static tools::wallet2::transfer_container make_transfers_container(size_t N) tools::wallet2::transfer_details &td = transfers.back(); td.m_block_height = 1000; td.m_spent = false; + td.m_txid = cryptonote::null_hash; + td.m_txid.data[0] = n & 0xff; + td.m_txid.data[1] = (n >> 8) & 0xff; + td.m_txid.data[2] = (n >> 16) & 0xff; + td.m_txid.data[3] = (n >> 24) & 0xff; } return transfers; }