diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 3db26cfc..50d45bca 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -4263,7 +4263,7 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, std::vector output_keys; scan_for_keys_context scan_context = AUTO_VAL_INIT(scan_context); - if(!get_output_keys_for_input_with_checks(tx, txin.amount, txin.key_offsets, output_keys, max_related_block_height, source_max_unlock_time_for_pos_coinbase)) + if(!get_output_keys_for_input_with_checks(tx, txin, output_keys, max_related_block_height, source_max_unlock_time_for_pos_coinbase)) { LOG_PRINT_L0("Failed to get output keys for input #" << in_index << " (amount = " << print_money(txin.amount) << ", key_offset.size = " << txin.key_offsets.size() << ")"); return false; @@ -4559,12 +4559,11 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, //TIME_MEASURE_START_PD(tx_check_inputs_loop_ch_in_get_keys_loop); std::vector output_keys; - std::vector key_offsets(1, txin.key_offset); scan_for_keys_context scan_contex = AUTO_VAL_INIT(scan_contex); uint64_t source_max_unlock_time_for_pos_coinbase_dummy = AUTO_VAL_INIT(source_max_unlock_time_for_pos_coinbase_dummy); if (!get_output_keys_for_input_with_checks(tx, txin, output_keys, max_related_block_height, source_max_unlock_time_for_pos_coinbase_dummy, scan_contex)) { - LOG_PRINT_L0("Failed to get output keys for input #" << in_index << " (amount = " << print_money(txin.amount) << ", key_offset.size = " << key_offsets.size() << ")"); + LOG_PRINT_L0("Failed to get output keys for input #" << in_index << " (amount = " << print_money(txin.amount) << ", key_offset.size = " << txin.key_offsets.size() << ")"); return false; } @@ -4599,7 +4598,7 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, CHECK_AND_ASSERT_THROW_MES(output_keys_ptrs.size() == 1, "Internal error: output_keys_ptrs.size() is not equal 1 for HTLC"); - return check_input_signature(tx, in_index, key_offsets, txin.amount, txin.k_image, txin.etc_details, tx_prefix_hash, sig, output_keys_ptrs); + return check_input_signature(tx, in_index, txin.amount, txin.k_image, txin.etc_details, tx_prefix_hash, sig, output_keys_ptrs); } //------------------------------------------------------------------ uint64_t blockchain_storage::get_adjusted_time() const @@ -6100,23 +6099,24 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, s if (p_max_related_block_height != nullptr) *p_max_related_block_height = 0; - CHECK_AND_ASSERT_MES(input_index < input_tx.vin.size() && input_tx.vin[input_index].type() == typeid(txin_to_key), false, "invalid input index: " << input_index); - const txin_to_key& input = boost::get(input_tx.vin[input_index]); + CHECK_AND_ASSERT_MES(input_index < input_tx.vin.size(), false, "invalid input index: " << input_index); + const txin_v& input_v = input_tx.vin[input_index]; + const txin_to_key& input_to_key = get_to_key_input_from_txin_v(input_v); // check case b1: key_image spent status in main chain, should be either non-spent or has spent height >= split_height - auto p = m_db_spent_keys.get(input.k_image); - CHECK_AND_ASSERT_MES(p == nullptr || *p >= split_height, false, "key image " << input.k_image << " has been already spent in main chain at height " << *p << ", split height: " << split_height); + auto p = m_db_spent_keys.get(input_to_key.k_image); + CHECK_AND_ASSERT_MES(p == nullptr || *p >= split_height, false, "key image " << input_to_key.k_image << " has been already spent in main chain at height " << *p << ", split height: " << split_height); TIME_MEASURE_START(ki_lookup_time); //check key_image in altchain //check among this alt block already collected key images first - if (collected_keyimages.find(input.k_image) != collected_keyimages.end()) + if (collected_keyimages.find(input_to_key.k_image) != collected_keyimages.end()) { // cases b2, b3 - LOG_ERROR("key image " << input.k_image << " already spent in this alt block"); + LOG_ERROR("key image " << input_to_key.k_image << " already spent in this alt block"); return false; } - auto ki_it = m_altblocks_keyimages.find(input.k_image); + auto ki_it = m_altblocks_keyimages.find(input_to_key.k_image); if (ki_it != m_altblocks_keyimages.end()) { //have some entry for this key image. Check if this key image belongs to this alt chain @@ -6126,18 +6126,18 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, s if (alt_chain_block_ids.find(h) != alt_chain_block_ids.end()) { // cases b2, b3 - LOG_ERROR("key image " << input.k_image << " already spent in altchain"); + LOG_ERROR("key image " << input_to_key.k_image << " already spent in altchain"); return false; } } } //update altchain with key image - collected_keyimages.insert(input.k_image); + collected_keyimages.insert(input_to_key.k_image); TIME_MEASURE_FINISH(ki_lookup_time); ki_lookuptime = ki_lookup_time; - std::vector abs_key_offsets = relative_output_offsets_to_absolute(input.key_offsets); - CHECK_AND_ASSERT_MES(abs_key_offsets.size() > 0 && abs_key_offsets.size() == input.key_offsets.size(), false, "internal error: abs_key_offsets.size()==" << abs_key_offsets.size() << ", input.key_offsets.size()==" << input.key_offsets.size()); + std::vector abs_key_offsets = relative_output_offsets_to_absolute(input_to_key.key_offsets); + CHECK_AND_ASSERT_MES(abs_key_offsets.size() > 0 && abs_key_offsets.size() == input_to_key.key_offsets.size(), false, "internal error: abs_key_offsets.size()==" << abs_key_offsets.size() << ", input_to_key.key_offsets.size()==" << input_to_key.key_offsets.size()); // eventually we should found all public keys for all outputs this input refers to, for checking ring signature std::vector pub_keys(abs_key_offsets.size(), null_pkey); @@ -6147,12 +6147,12 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, s uint64_t global_outs_for_amount = 0; //figure out if this amount touched alt_chain amount's index and if it is, get bool amount_touched_altchain = false; - //auto abg_it = abei.gindex_lookup_table.find(input.amount); + //auto abg_it = abei.gindex_lookup_table.find(input_to_key.amount); //if (abg_it == abei.gindex_lookup_table.end()) if (!alt_chain.empty()) { - auto abg_it = alt_chain.back()->second.gindex_lookup_table.find(input.amount); + auto abg_it = alt_chain.back()->second.gindex_lookup_table.find(input_to_key.amount); if (abg_it != alt_chain.back()->second.gindex_lookup_table.end()) { amount_touched_altchain = true; @@ -6163,13 +6163,13 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, s else { //quite easy, - global_outs_for_amount = m_db_outputs.get_item_size(input.amount); + global_outs_for_amount = m_db_outputs.get_item_size(input_to_key.amount); } } else { //quite easy, - global_outs_for_amount = m_db_outputs.get_item_size(input.amount); + global_outs_for_amount = m_db_outputs.get_item_size(input_to_key.amount); } CHECK_AND_ASSERT_MES(pub_keys.size() == abs_key_offsets.size(), false, "pub_keys.size()==" << pub_keys.size() << " != abs_key_offsets.size()==" << abs_key_offsets.size()); // just a little bit of paranoia @@ -6184,7 +6184,7 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, s { uint64_t offset_gindex = boost::get(off); CHECK_AND_ASSERT_MES(offset_gindex < global_outs_for_amount, false, - "invalid global output index " << offset_gindex << " for amount=" << input.amount << + "invalid global output index " << offset_gindex << " for amount=" << input_to_key.amount << ", max is " << global_outs_for_amount << ", referred to by offset #" << pk_n << ", amount_touched_altchain = " << amount_touched_altchain); @@ -6193,7 +6193,7 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, s bool found_the_key = false; for (auto alt_it = alt_chain.rbegin(); alt_it != alt_chain.rend(); alt_it++) { - auto it_aag = (*alt_it)->second.gindex_lookup_table.find(input.amount); + auto it_aag = (*alt_it)->second.gindex_lookup_table.find(input_to_key.amount); if (it_aag == (*alt_it)->second.gindex_lookup_table.end()) { CHECK_AND_ASSERT_MES(alt_it != alt_chain.rbegin(), false, "internal error: was marked as amount_touched_altchain but unable to find on first entry"); @@ -6203,11 +6203,11 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, s if (offset_gindex >= it_aag->second) { //GOT IT!! - //TODO: At the moment we ignore check of mix_attr again mixing to simplify alt chain check, but in future consider it for stronger validation + //TODO: At the moment we ignore check of mix_attr against mixing to simplify alt chain check, but in future consider it for stronger validation uint64_t local_offset = offset_gindex - it_aag->second; auto& alt_keys = (*alt_it)->second.outputs_pub_keys; - CHECK_AND_ASSERT_MES(local_offset < alt_keys[input.amount].size(), false, "Internal error: local_offset=" << local_offset << " while alt_keys[" << input.amount << " ].size()=" << alt_keys.size()); - pk = alt_keys[input.amount][local_offset]; + CHECK_AND_ASSERT_MES(local_offset < alt_keys[input_to_key.amount].size(), false, "Internal error: local_offset=" << local_offset << " while alt_keys[" << input_to_key.amount << " ].size()=" << alt_keys.size()); + pk = alt_keys[input_to_key.amount][local_offset]; pub_key_pointers.push_back(&pk); found_the_key = true; break; @@ -6217,8 +6217,8 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, s break; //otherwise lookup in main chain index } - auto p = m_db_outputs.get_subitem(input.amount, offset_gindex); - CHECK_AND_ASSERT_MES(p != nullptr, false, "global output was not found, amount: " << input.amount << ", gindex: " << offset_gindex << ", referred to by offset #" << pk_n); + auto p = m_db_outputs.get_subitem(input_to_key.amount, offset_gindex); + CHECK_AND_ASSERT_MES(p != nullptr, false, "global output was not found, amount: " << input_to_key.amount << ", gindex: " << offset_gindex << ", referred to by offset #" << pk_n); tx_id = p->tx_id; out_n = p->out_no; } @@ -6254,7 +6254,7 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, s } // do input checks (attachment_info, ring signature and extra signature, etc.) - r = check_input_signature(input_tx, input_index, input, input_tx_hash, input_sigs, pub_key_pointers); + r = check_input_signature(input_tx, input_index, input_to_key, input_tx_hash, input_sigs, pub_key_pointers); CHECK_AND_ASSERT_MES(r, false, "to_key input validation failed"); // TODO: consider checking input_tx for valid extra attachment info as it's checked in check_tx_inputs() @@ -6485,7 +6485,7 @@ bool blockchain_storage::validate_alt_block_txs(const block& b, const crypto::ha CHECK_AND_ASSERT_MES(tx.signatures.size() == tx.vin.size(), false, "invalid tx: tx.signatures.size() == " << tx.signatures.size() << ", tx.vin.size() == " << tx.vin.size()); for (size_t n = 0; n < tx.vin.size(); ++n) { - if (tx.vin[n].type() == typeid(txin_to_key)) + if (tx.vin[n].type() == typeid(txin_to_key) || tx.vin[n].type() == typeid(txin_htlc)) { uint64_t ki_lookup = 0; r = validate_alt_block_input(tx, collected_keyimages, id, tx_id, n, tx.signatures[n], split_height, alt_chain, alt_chain_block_ids, ki_lookup); diff --git a/src/currency_core/blockchain_storage.h b/src/currency_core/blockchain_storage.h index 66fd5a72..a892c1fa 100644 --- a/src/currency_core/blockchain_storage.h +++ b/src/currency_core/blockchain_storage.h @@ -686,26 +686,10 @@ namespace currency template bool blockchain_storage::scan_outputkeys_for_indexes(const transaction &validated_tx, const txin_v& verified_input, visitor_t& vis, uint64_t& max_related_block_height, scan_for_keys_context& scan_context) const { - std::vector key_offsets_dummy; - uint64_t amount = 0; - const std::vector& key_offsets = [&] -> const std::vector& - { - if (verified_input.type() == typeid(txin_htlc)) - { - //hltc - const txin_htlc& htlc = boost::get(verified_input); - key_offsets_dummy.push_back(htlc.key_offset); - amount = htlc.amount; - return key_offsets_dummy; - } - else if (verified_input.type() == typeid(txin_to_key)) - { - //regular to key output - const txin_to_key& to_key = boost::get(verified_input); - amount = to_key.amount; - return to_key.key_offsets; - } - }; + const txin_to_key& input_to_key = get_to_key_input_from_txin_v(verified_input); + + uint64_t amount = input_to_key.amount; + const std::vector& key_offsets = input_to_key.key_offsets; CRITICAL_REGION_LOCAL(m_read_lock); TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_get_item_size); @@ -757,6 +741,8 @@ namespace currency { //HTLC input CAN'T refer to regular to_key output CHECK_AND_ASSERT_MES(verified_input.type() != typeid(txin_htlc), false, "[TXOUT_TO_KEY]: Unexpected output type of HTLC input"); + + CHECKED_GET_SPECIFIC_VARIANT(tx_ptr->tx.vout[n].target, const txout_to_key, outtk, false); //fix for burned money patch_out_if_needed(const_cast(outtk), tx_id, n); diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h index a0c16f56..cb815ade 100644 --- a/src/currency_core/currency_basic.h +++ b/src/currency_core/currency_basic.h @@ -223,21 +223,13 @@ namespace currency END_SERIALIZE() }; - struct txin_htlc + struct txin_htlc: public txin_to_key { - uint64_t amount; std::string hltc_origin; - txout_ref_v key_offset; - crypto::key_image k_image; // double spending protection - std::vector etc_details; //this flag used when TX_FLAG_SIGNATURE_MODE_SEPARATE flag is set, point to which amount of outputs(starting from zero) used in signature - BEGIN_SERIALIZE_OBJECT() - VARINT_FIELD(amount) FIELD(hltc_origin) - FIELD(key_offset) - FIELD(k_image) - FIELD(etc_details) - END_SERIALIZE() + FIELDS(*static_cast(this)) + END_SERIALIZE() }; struct txin_multisig diff --git a/src/currency_core/currency_boost_serialization.h b/src/currency_core/currency_boost_serialization.h index ec70a988..25cce5e8 100644 --- a/src/currency_core/currency_boost_serialization.h +++ b/src/currency_core/currency_boost_serialization.h @@ -100,7 +100,7 @@ namespace boost a & x.etc_details; a & x.hltc_origin; a & x.k_image; - a & x.key_offset; + a & x.key_offsets; } template diff --git a/src/currency_core/currency_format_utils_abstract.h b/src/currency_core/currency_format_utils_abstract.h index 5f1c7cf6..8f562120 100644 --- a/src/currency_core/currency_format_utils_abstract.h +++ b/src/currency_core/currency_format_utils_abstract.h @@ -129,6 +129,22 @@ namespace currency } return found; } + + const txin_to_key& get_to_key_input_from_txin_v(const txin_v& in_v) + { + if (in_v.type() == typeid(txin_to_key)) + { + return boost::get(in_v); + } + else if (in_v.type() == typeid(txin_htlc)) + { + const txin_htlc& in = boost::get(in_v); + return static_cast(in); + } + else { + ASSERT_MES_AND_THROW("[get_to_key_input_from_txin_v] Wrong type " << in_v.type().name()); + } + } //--------------------------------------------------------------- template bool check_allowed_types_in_variant_container(const variant_container_t& container, const std::unordered_set& allowed_types, bool elements_must_be_unique = true)