diff --git a/src/common/variant_helper.h b/src/common/variant_helper.h index 03d8746a..ecbca5a4 100644 --- a/src/common/variant_helper.h +++ b/src/common/variant_helper.h @@ -4,7 +4,8 @@ #pragma once -#define VARIANT_SWITCH_BEGIN(v_type_obj) {decltype(v_type_obj)& local_reference_eokcmeokmeokcm = v_type_obj; if(false) {; +#define VARIANT_SWITCH_BEGIN(v_type_obj) {auto & local_reference_eokcmeokmeokcm = v_type_obj; if(false) {; +#define VARIANT_CASE_CONST(v_type, typed_name) } else if(local_reference_eokcmeokmeokcm.type() == typeid(v_type)) { const v_type& typed_name = boost::get(local_reference_eokcmeokmeokcm); #define VARIANT_CASE(v_type, typed_name) } else if(local_reference_eokcmeokmeokcm.type() == typeid(v_type)) { v_type& typed_name = boost::get(local_reference_eokcmeokmeokcm); #define VARIANT_CASE_TV(v_type) VARIANT_CASE(v_type, tv) #define VARIANT_CASE_OTHER() } else { @@ -26,9 +27,10 @@ usage: VARIANT_SWITCH_END(); VARIANT_SWITCH_BEGIN(o); - VARIANT_CASE(txout_to_key, o); - VARIANT_CASE_TV(txout_multisig); - VARIANT_CASE_TV(txout_htlc); + VARIANT_CASE_CONST(txout_to_key, o); + VARIANT_CASE_CONST(txout_multisig, ms); + VARIANT_CASE_CONST(txout_htlc, htlc); + VARIANT_CASE_THROW_ON_OTHER(); VARIANT_SWITCH_END(); diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 20bc4f0e..667fa2fc 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -38,6 +38,7 @@ #include "crypto/RIPEMD160_helper.h" #include "crypto/bitcoin/sha256_helper.h" + #undef LOG_DEFAULT_CHANNEL #define LOG_DEFAULT_CHANNEL "core" ENABLE_CHANNEL_BY_DEFAULT("core"); @@ -610,13 +611,13 @@ bool blockchain_storage::prune_ring_signatures_and_attachments(uint64_t height, transaction_chain_entry lolcal_chain_entry = *it; VARIANT_SWITCH_BEGIN(lolcal_chain_entry.tx.signature); - VARIANT_CASE(void_sig, v); + VARIANT_CASE_CONST(void_sig, v); VARIANT_CASE(NLSAG_sig, signatures) { signatures_pruned += signatures.s.size(); signatures.s.clear(); } - VARIANT_CASE(zarcanum_sig, s); + VARIANT_CASE_CONST(zarcanum_sig, s); //@#@ VARIANT_SWITCH_END(); @@ -2488,7 +2489,7 @@ bool blockchain_storage::add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPU const transaction& tx = tx_ptr->tx; VARIANT_SWITCH_BEGIN(tx.vout[out_ptr->out_no]); - VARIANT_CASE(tx_out_bare, o) + VARIANT_CASE_CONST(tx_out_bare, o) { if (o.target.type() == typeid(txout_htlc)) { @@ -2527,7 +2528,7 @@ bool blockchain_storage::add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPU oen.global_amount_index = i; oen.out_key = otk.key; } - VARIANT_CASE_TV(tx_out_zarcanum) + VARIANT_CASE_CONST(tx_out_zarcanum, toz) //@#@ VARIANT_SWITCH_END(); @@ -3034,10 +3035,10 @@ void blockchain_storage::print_blockchain_outs_stats() const if (!spent)// && p_tx->tx.vout[output_entry.out_no].target.type() == typeid(txout_to_key)) { VARIANT_SWITCH_BEGIN(p_tx->tx.vout[output_entry.out_no]); - VARIANT_CASE(tx_out_bare, o) + VARIANT_CASE_CONST(tx_out_bare, o) if (boost::get(o.target).mix_attr != CURRENCY_TO_KEY_OUT_FORCED_NO_MIX) ++stat.mixable; - VARIANT_CASE_TV(tx_out_zarcanum) + VARIANT_CASE_CONST(tx_out_zarcanum, toz) //@#@ VARIANT_SWITCH_END(); } @@ -3354,7 +3355,7 @@ bool blockchain_storage::push_transaction_to_global_outs_index(const transaction BOOST_FOREACH(const auto& otv, tx.vout) { VARIANT_SWITCH_BEGIN(otv); - VARIANT_CASE(tx_out_bare, ot) + VARIANT_CASE_CONST(tx_out_bare, ot) if (ot.target.type() == typeid(txout_to_key) || ot.target.type() == typeid(txout_htlc)) { m_db_outputs.push_back_item(ot.amount, global_output_entry::construct(tx_id, i)); @@ -3374,7 +3375,7 @@ bool blockchain_storage::push_transaction_to_global_outs_index(const transaction m_db_multisig_outs.set(multisig_out_id, ms_output_entry::construct(tx_id, i)); global_indexes.push_back(0); // just stub to make other code easier } - VARIANT_CASE_TV(tx_out_zarcanum) + VARIANT_CASE_CONST(tx_out_zarcanum, toz) //@#@ VARIANT_CASE_THROW_ON_OTHER(); VARIANT_SWITCH_END(); @@ -3406,7 +3407,7 @@ bool blockchain_storage::get_outs(uint64_t amount, std::list CHECK_AND_ASSERT_MES(tx_ptr->tx.vout.size() > out_entry_ptr->out_no, false, "transactions outs global index consistency broken: index in tx_outx == " << out_entry_ptr->out_no << " is greather than tx.vout size == " << tx_ptr->tx.vout.size() << ", for amount: " << amount << ", gindex: " << i); //CHECK_AND_ASSERT_MES(tx_ptr->tx.vout[out_entry_ptr->out_no].target.type() == typeid(txout_to_key), false, "transactions outs global index consistency broken: out #" << out_entry_ptr->out_no << " in tx " << out_entry_ptr->tx_id << " has wrong type, for amount: " << amount << ", gindex: " << i); VARIANT_SWITCH_BEGIN(tx_ptr->tx.vout[out_entry_ptr->out_no]); - VARIANT_CASE(tx_out_bare, o) + VARIANT_CASE_CONST(tx_out_bare, o) if (o.target.type() == typeid(txout_to_key)) { pkeys.push_back(boost::get(o.target).key); @@ -3415,7 +3416,7 @@ bool blockchain_storage::get_outs(uint64_t amount, std::list { pkeys.push_back(boost::get(o.target).pkey_redeem); } - VARIANT_CASE_TV(tx_out_zarcanum) + VARIANT_CASE_CONST(tx_out_zarcanum, toz) //@#@ VARIANT_CASE_THROW_ON_OTHER(); VARIANT_SWITCH_END(); @@ -3431,7 +3432,7 @@ bool blockchain_storage::pop_transaction_from_global_index(const transaction& tx BOOST_REVERSE_FOREACH(const auto& otv, tx.vout) { VARIANT_SWITCH_BEGIN(otv); - VARIANT_CASE(tx_out_bare, ot) + VARIANT_CASE_CONST(tx_out_bare, ot) if (ot.target.type() == typeid(txout_to_key) || ot.target.type() == typeid(txout_htlc)) { uint64_t sz = m_db_outputs.get_item_size(ot.amount); @@ -3450,7 +3451,7 @@ bool blockchain_storage::pop_transaction_from_global_index(const transaction& tx bool res = m_db_multisig_outs.erase_validate(multisig_out_id); CHECK_AND_ASSERT_MES(res, false, "Internal error: multisig out not found, multisig_out_id " << multisig_out_id << "in multisig outs index"); } - VARIANT_CASE_TV(tx_out_zarcanum) + VARIANT_CASE_CONST(tx_out_zarcanum, toz) //@#@ VARIANT_CASE_THROW_ON_OTHER(); VARIANT_SWITCH_END(); @@ -4188,12 +4189,12 @@ bool blockchain_storage::print_tx_outputs_lookup(const crypto::hash& tx_id)const for (uint64_t i = 0; i!= tx_ptr->tx.vout.size();i++) { VARIANT_SWITCH_BEGIN(tx_ptr->tx.vout[i]); - VARIANT_CASE(tx_out_bare, o) + VARIANT_CASE_CONST(tx_out_bare, o) strm_tx << "[" << i << "]: " << print_money(o.amount) << ENDL; if (o.target.type() != typeid(currency::txout_to_key)) continue; usage_stat[o.amount][tx_ptr->m_global_output_indexes[i]]; - VARIANT_CASE_TV(tx_out_zarcanum) + VARIANT_CASE_CONST(tx_out_zarcanum, toz) //@#@ VARIANT_SWITCH_END(); } @@ -4296,22 +4297,21 @@ bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::ha if (!m_is_in_checkpoint_zone) { VARIANT_SWITCH_BEGIN(tx.signature); - VARIANT_CASE(void_sig, v); - VARIANT_CASE(NLSAG_sig, signatures); + VARIANT_CASE_CONST(void_sig, v); + VARIANT_CASE_CONST(NLSAG_sig, signatures); { CHECK_AND_ASSERT_MES(sig_index < signatures.s.size(), false, "Wrong transaction: missing signature entry for input #" << sig_index << " tx: " << tx_prefix_hash); psig = &signatures.s[sig_index]; } - VARIANT_CASE(zarcanum_sig, s); + VARIANT_CASE_CONST(zarcanum_sig, s); //@#@ VARIANT_SWITCH_END(); } - if (txin.type() == typeid(txin_to_key)) + VARIANT_SWITCH_BEGIN(txin); + VARIANT_CASE_CONST(txin_to_key, in_to_key) { - const txin_to_key& in_to_key = boost::get(txin); - CHECK_AND_ASSERT_MES(in_to_key.key_offsets.size(), false, "Empty in_to_key.key_offsets for input #" << sig_index << " tx: " << tx_prefix_hash); TIME_MEASURE_START_PD(tx_check_inputs_loop_kimage_check); if (have_tx_keyimg_as_spent(in_to_key.k_image)) @@ -4321,22 +4321,21 @@ bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::ha } TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_kimage_check); uint64_t max_unlock_time = 0; - if (!check_tx_input(tx, sig_index, in_to_key, tx_prefix_hash, *psig, max_used_block_height, max_unlock_time)) + if (!check_tx_input(tx, sig_index, in_to_key, tx_prefix_hash, max_used_block_height, max_unlock_time)) { LOG_ERROR("Failed to validate input #" << sig_index << " tx: " << tx_prefix_hash); return false; } } - else if (txin.type() == typeid(txin_multisig)) + VARIANT_CASE_CONST(txin_multisig, in_ms) { - const txin_multisig& in_ms = boost::get(txin); - if (!check_tx_input(tx, sig_index, in_ms, tx_prefix_hash, *psig, max_used_block_height)) + if (!check_tx_input(tx, sig_index, in_ms, tx_prefix_hash, max_used_block_height)) { LOG_ERROR("Failed to validate multisig input #" << sig_index << " (ms out id: " << in_ms.multisig_out_id << ") in tx: " << tx_prefix_hash); return false; } } - else if (txin.type() == typeid(txin_htlc)) + VARIANT_CASE_CONST(txin_htlc, in_htlc) { if (!is_after_hardfork_3_zone()) { @@ -4344,7 +4343,6 @@ bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::ha return false; } - const txin_htlc& in_htlc = boost::get(txin); CHECK_AND_ASSERT_MES(in_htlc.key_offsets.size(), false, "Empty in_to_key.key_offsets for input #" << sig_index << " tx: " << tx_prefix_hash); TIME_MEASURE_START_PD(tx_check_inputs_loop_kimage_check); if (have_tx_keyimg_as_spent(in_htlc.k_image)) @@ -4353,12 +4351,15 @@ bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::ha return false; } TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_kimage_check); - if (!check_tx_input(tx, sig_index, in_htlc, tx_prefix_hash, *psig, max_used_block_height)) + if (!check_tx_input(tx, sig_index, in_htlc, tx_prefix_hash, max_used_block_height)) { LOG_ERROR("Failed to validate multisig input #" << sig_index << " (ms out id: " << obj_to_json_str(in_htlc) << ") in tx: " << tx_prefix_hash); return false; } } + VARIANT_CASE_THROW_ON_OTHER(); + VARIANT_SWITCH_END(); + sig_index++; } TIME_MEASURE_FINISH_PD(tx_check_inputs_loop); @@ -4367,11 +4368,11 @@ bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::ha if (!m_is_in_checkpoint_zone) { VARIANT_SWITCH_BEGIN(tx.signature); - VARIANT_CASE(NLSAG_sig, signatures) + VARIANT_CASE_CONST(NLSAG_sig, signatures) { - CHECK_AND_ASSERT_MES(signatures.size() == sig_index, false, "tx signatures count differs from inputs"); + CHECK_AND_ASSERT_MES(signatures.s.size() == sig_index, false, "tx signatures count differs from inputs"); } - VARIANT_CASE(zarcanum_sig, s); + VARIANT_CASE_CONST(zarcanum_sig, s); //@#@ VARIANT_CASE_THROW_ON_OTHER(); VARIANT_SWITCH_END(); @@ -4390,7 +4391,7 @@ bool blockchain_storage::is_tx_spendtime_unlocked(uint64_t unlock_time) const return currency::is_tx_spendtime_unlocked(unlock_time, get_current_blockchain_size(), m_core_runtime_config.get_core_time()); } //------------------------------------------------------------------ -bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase) const +bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase) const { CRITICAL_REGION_LOCAL(m_read_lock); @@ -4410,7 +4411,7 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, for (auto& ptr : output_keys) output_keys_ptrs.push_back(&ptr); - return check_input_signature(tx, in_index, txin, tx_prefix_hash, sig, output_keys_ptrs); + return check_input_signature(tx, in_index, txin, tx_prefix_hash, output_keys_ptrs); } //---------------------------------------------------------------- struct outputs_visitor @@ -4497,7 +4498,7 @@ bool blockchain_storage::get_output_keys_for_input_with_checks(const transaction //------------------------------------------------------------------ // Note: this function can be used for checking to_key inputs against either main chain or alt chain, that's why it has output_keys_ptrs parameter // Doesn't check spent flags, the caller must check it. -bool blockchain_storage::check_input_signature(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, const std::vector& output_keys_ptrs) const +bool blockchain_storage::check_input_signature(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& output_keys_ptrs) const { if (txin.key_offsets.size() != output_keys_ptrs.size()) { @@ -4505,7 +4506,7 @@ bool blockchain_storage::check_input_signature(const transaction& tx, size_t in_ return false; } - return check_input_signature(tx, in_index, /*txin.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.key_offsets,*/ txin.amount, txin.k_image, txin.etc_details, tx_prefix_hash, output_keys_ptrs); } //------------------------------------------------------------------ bool blockchain_storage::check_input_signature(const transaction& tx, @@ -4514,7 +4515,6 @@ bool blockchain_storage::check_input_signature(const transaction& tx, const crypto::key_image& in_k_image, const std::vector& in_etc_details, const crypto::hash& tx_prefix_hash, - const std::vector& sig, const std::vector& output_keys_ptrs) const { CRITICAL_REGION_LOCAL(m_read_lock); @@ -4524,6 +4524,10 @@ bool blockchain_storage::check_input_signature(const transaction& tx, if(m_is_in_checkpoint_zone) return true; + CHECK_AND_ASSERT_MES(tx.signature.type() == typeid(NLSAG_sig), false, "Unexpected type of sig in check_input_signature: " << tx.signature.type().name()); + auto s = boost::get(tx.signature).s; + CHECK_AND_ASSERT_MES(s.size() > in_index, false, "Failed to check s.size(){" << s.size() << "} > in_index {" << in_index << "}" ); + const std::vector& sig = s[in_index]; if (get_tx_flags(tx) & TX_FLAG_SIGNATURE_MODE_SEPARATE) { // check attachments, mentioned directly in this input @@ -4572,7 +4576,7 @@ bool blockchain_storage::check_input_signature(const transaction& tx, //------------------------------------------------------------------ // Note: this function doesn't check spent flags by design (to be able to use either for main chain and alt chains). // The caller MUST check spent flags. -bool blockchain_storage::check_ms_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, const transaction& source_tx, size_t out_n) const +bool blockchain_storage::check_ms_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const transaction& source_tx, size_t out_n) const { #define LOC_CHK(cond, msg) CHECK_AND_ASSERT_MES(cond, false, "ms input check failed: ms_id: " << txin.multisig_out_id << ", input #" << in_index << " in tx " << tx_prefix_hash << ", refers to ms output #" << out_n << " in source tx " << get_transaction_hash(source_tx) << ENDL << msg) CRITICAL_REGION_LOCAL(m_read_lock); @@ -4581,7 +4585,7 @@ bool blockchain_storage::check_ms_input(const transaction& tx, size_t in_index, LOC_CHK(is_tx_spendtime_unlocked(unlock_time), "Source transaction is LOCKED! unlock_time: " << unlock_time << ", now is " << m_core_runtime_config.get_core_time() << ", blockchain size is " << get_current_blockchain_size()); LOC_CHK(source_tx.vout.size() > out_n, "internal error: out_n==" << out_n << " is out-of-bounds of source_tx.vout, size=" << source_tx.vout.size()); - LOC_CHK(source_tx.vout[out_n].type() !== typeid(tx_out_bare), "internal error: out_n==" << out_n << " has unexpected type: " << source_tx.vout[out_n].type().name()); + LOC_CHK(source_tx.vout[out_n].type() != typeid(tx_out_bare), "internal error: out_n==" << out_n << " has unexpected type: " << source_tx.vout[out_n].type().name()); const tx_out_bare& source_tx_out = boost::get(source_tx.vout[out_n]); const txout_multisig& source_ms_out_target = boost::get(source_tx_out.target); @@ -4610,16 +4614,15 @@ bool blockchain_storage::check_ms_input(const transaction& tx, size_t in_index, // make sure normal tx does not have extra_attachment_info in etc_details LOC_CHK(!have_type_in_variant_container(txin.etc_details), "Incorrect using of extra_attachment_info in etc_details in input #" << in_index << " for tx " << tx_prefix_hash); } - + bool need_to_check_extra_sign = false; VARIANT_SWITCH_BEGIN(tx.signature); - VARIANT_CASE(void_sig, v); - VARIANT_CASE(NLSAG_sig, signatures) + VARIANT_CASE_CONST(void_sig, v); + VARIANT_CASE_CONST(NLSAG_sig, signatures) { - LOC_CHK(signatures.size() > in_index, "ms input index is out of signatures container bounds, signatures.size() = " << signatures.size()); + LOC_CHK(signatures.s.size() > in_index, "ms input index is out of signatures container bounds, signatures.size() = " << signatures.s.size()); const std::vector& input_signatures = signatures.s[in_index]; size_t expected_signatures_count = txin.sigs_count; - bool need_to_check_extra_sign = false; if (get_tx_flags(tx)&TX_FLAG_SIGNATURE_MODE_SEPARATE && in_index == tx.vin.size() - 1) // last input in TX_FLAG_SIGNATURE_MODE_SEPARATE must contain one more signature to ensure that tx was completed by an authorized subject { expected_signatures_count++; @@ -4652,21 +4655,21 @@ bool blockchain_storage::check_ms_input(const transaction& tx, size_t in_index, } } } - VARIANT_CASE(zarcanum_sig, s); + VARIANT_CASE_CONST(zarcanum_sig, s); //@#@ VARIANT_SWITCH_END(); if (need_to_check_extra_sign) { VARIANT_SWITCH_BEGIN(tx.signature); - VARIANT_CASE(void_sig, v); - VARIANT_CASE(NLSAG_sig, signatures) + VARIANT_CASE_CONST(void_sig, v); + VARIANT_CASE_CONST(NLSAG_sig, signatures) { //here we check extra signature to validate that transaction was finilized by authorized subject bool r = crypto::check_signature(tx_prefix_hash, get_tx_pub_key_from_extra(tx), signatures.s[in_index].back()); LOC_CHK(r, "failed to check extra signature for last out with TX_FLAG_SIGNATURE_MODE_SEPARATE"); } - VARIANT_CASE(zarcanum_sig, s); + VARIANT_CASE_CONST(zarcanum_sig, s); //@#@ VARIANT_SWITCH_END(); @@ -4677,7 +4680,7 @@ bool blockchain_storage::check_ms_input(const transaction& tx, size_t in_index, } //------------------------------------------------------------------ -bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, uint64_t& max_related_block_height) const +bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height) const { CRITICAL_REGION_LOCAL(m_read_lock); @@ -4694,12 +4697,12 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, auto source_tx_ptr = m_db_transactions.find(source_tx_id); LOC_CHK(source_tx_ptr, "Can't find source transaction"); LOC_CHK(source_tx_ptr->tx.vout.size() > n, "ms output index is incorrect, source tx's vout size is " << source_tx_ptr->tx.vout.size()); - LOC_CHK(source_tx_ptr->tx.vout[n].type() != = typeid(tx_out_bare), "internal error: out_n==" << n << " has unexpected type: " << source_tx_ptr->tx.vout[n].type().name()); + LOC_CHK(source_tx_ptr->tx.vout[n].type() != typeid(tx_out_bare), "internal error: out_n==" << n << " has unexpected type: " << source_tx_ptr->tx.vout[n].type().name()); LOC_CHK(boost::get(source_tx_ptr->tx.vout[n]).target.type() == typeid(txout_multisig), "ms output has wrong type, txout_multisig expected"); LOC_CHK(source_tx_ptr->m_spent_flags.size() > n, "Internal error, m_spent_flags size (" << source_tx_ptr->m_spent_flags.size() << ") less then expected, n: " << n); LOC_CHK(source_tx_ptr->m_spent_flags[n] == false, "Internal error, ms output is already spent"); // should never happen as multisig_ptr->spent_height is checked above - if (!check_ms_input(tx, in_index, txin, tx_prefix_hash, sig, source_tx_ptr->tx, n)) + if (!check_ms_input(tx, in_index, txin, tx_prefix_hash, source_tx_ptr->tx, n)) return false; max_related_block_height = source_tx_ptr->m_keeper_block_height; @@ -4708,7 +4711,7 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, #undef LOC_CHK } //------------------------------------------------------------------ -bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_htlc& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, uint64_t& max_related_block_height)const +bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_htlc& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height)const { CRITICAL_REGION_LOCAL(m_read_lock); @@ -4753,8 +4756,19 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, output_keys_ptrs.push_back(&ptr); 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, txin.amount, txin.k_image, txin.etc_details, tx_prefix_hash, sig, output_keys_ptrs); + + VARIANT_SWITCH_BEGIN(tx.signature); + VARIANT_CASE_CONST(NLSAG_sig, signatures); + { + CHECK_AND_ASSERT_MES(signatures.s.size() > in_index, false, "Unexpeted number of singatures in NLSAG_sig: " << signatures.s.size() << ", expected at least: " << in_index); + return check_input_signature(tx, in_index, txin.amount, txin.k_image, txin.etc_details, tx_prefix_hash, output_keys_ptrs); + } + VARIANT_CASE_CONST(zarcanum_sig, s); + //@#@ TODO + return false; + VARIANT_CASE_THROW_ON_OTHER(); + VARIANT_SWITCH_END(); + return false; } //------------------------------------------------------------------ uint64_t blockchain_storage::get_adjusted_time() const @@ -5054,13 +5068,13 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti for (const auto out : tx.vout) { VARIANT_SWITCH_BEGIN(out); - VARIANT_CASE(tx_out_bare, o) + VARIANT_CASE_CONST(tx_out_bare, o) if (o.target.type() == typeid(txout_htlc)) { if (!var_is_after_hardfork_3_zone) return false; } - VARIANT_CASE_TV(tx_out_zarcanum) + VARIANT_CASE_CONST(tx_out_zarcanum, toz) if (!var_is_after_hardfork_4_zone) return false; VARIANT_SWITCH_END(); @@ -5115,9 +5129,9 @@ bool blockchain_storage::validate_pos_coinbase_outs_unlock_time(const transactio if (unlock_value >= source_max_unlock_time) { VARIANT_SWITCH_BEGIN(miner_tx.vout[i]); - VARIANT_CASE(tx_out_bare, o) + VARIANT_CASE_CONST(tx_out_bare, o) amount_of_coins_in_unlock_in_range += o.amount; - VARIANT_CASE_TV(tx_out_zarcanum) + VARIANT_CASE_CONST(tx_out_zarcanum, toz) //@#@ VARIANT_SWITCH_END(); } @@ -5205,37 +5219,30 @@ bool blockchain_storage::validate_pos_block(const block& b, uint64_t max_related_block_height = 0; const txin_to_key& coinstake_in = boost::get(b.miner_tx.vin[1]); - VARIANT_SWITCH_BEGIN(b.miner_tx.signature); - VARIANT_CASE(void_sig, v); - VARIANT_CASE(NLSAG_sig, signatures) + if (!for_altchain) { - CHECK_AND_ASSERT_MES(signatures.s.size() == 1, false, "PoS block's miner_tx has incorrect signatures size = " << signatures.s.size() << ", block_id = " << get_block_hash(b)); - if (!for_altchain) - { - // Do coinstake input validation for main chain only. - // Txs in alternative PoS blocks (including miner_tx) are validated by validate_alt_block_txs() - uint64_t source_max_unlock_time_for_pos_coinbase = 0; - r = check_tx_input(b.miner_tx, 1, coinstake_in, id, signatures.s[0], max_related_block_height, source_max_unlock_time_for_pos_coinbase); - CHECK_AND_ASSERT_MES(r, false, "Failed to validate coinstake input in miner tx, block_id = " << get_block_hash(b)); + // Do coinstake input validation for main chain only. + // Txs in alternative PoS blocks (including miner_tx) are validated by validate_alt_block_txs() + uint64_t source_max_unlock_time_for_pos_coinbase = 0; + r = check_tx_input(b.miner_tx, 1, coinstake_in, id, max_related_block_height, source_max_unlock_time_for_pos_coinbase); + CHECK_AND_ASSERT_MES(r, false, "Failed to validate coinstake input in miner tx, block_id = " << get_block_hash(b)); - if (get_block_height(b) > m_core_runtime_config.hard_forks.hard_fork_01_starts_after_height) - { - uint64_t last_pow_h = get_last_x_block_height(false); - CHECK_AND_ASSERT_MES(max_related_block_height <= last_pow_h, false, "Failed to validate coinbase in PoS block, condition failed: max_related_block_height(" << max_related_block_height << ") <= last_pow_h(" << last_pow_h << ")"); - //let's check that coinbase amount and unlock time - r = validate_pos_coinbase_outs_unlock_time(b.miner_tx, coinstake_in.amount, source_max_unlock_time_for_pos_coinbase); - CHECK_AND_ASSERT_MES(r, false, "Failed to validate_pos_coinbase_outs_unlock_time() in miner tx, block_id = " << get_block_hash(b) - << "source_max_unlock_time_for_pos_coinbase=" << source_max_unlock_time_for_pos_coinbase); - } - else - { - CHECK_AND_ASSERT_MES(is_tx_spendtime_unlocked(source_max_unlock_time_for_pos_coinbase), false, "Failed to validate coinbase in PoS block, condition failed: is_tx_spendtime_unlocked(source_max_unlock_time_for_pos_coinbase)(" << source_max_unlock_time_for_pos_coinbase << ")"); - } + if (get_block_height(b) > m_core_runtime_config.hard_forks.hard_fork_01_starts_after_height) + { + uint64_t last_pow_h = get_last_x_block_height(false); + CHECK_AND_ASSERT_MES(max_related_block_height <= last_pow_h, false, "Failed to validate coinbase in PoS block, condition failed: max_related_block_height(" << max_related_block_height << ") <= last_pow_h(" << last_pow_h << ")"); + //let's check that coinbase amount and unlock time + r = validate_pos_coinbase_outs_unlock_time(b.miner_tx, coinstake_in.amount, source_max_unlock_time_for_pos_coinbase); + CHECK_AND_ASSERT_MES(r, false, "Failed to validate_pos_coinbase_outs_unlock_time() in miner tx, block_id = " << get_block_hash(b) + << "source_max_unlock_time_for_pos_coinbase=" << source_max_unlock_time_for_pos_coinbase); + } + else + { + CHECK_AND_ASSERT_MES(is_tx_spendtime_unlocked(source_max_unlock_time_for_pos_coinbase), false, "Failed to validate coinbase in PoS block, condition failed: is_tx_spendtime_unlocked(source_max_unlock_time_for_pos_coinbase)(" << source_max_unlock_time_for_pos_coinbase << ")"); } } - VARIANT_CASE(zarcanum_sig, s); - //@#@ - VARIANT_SWITCH_END(); + + uint64_t block_height = for_altchain ? split_height + alt_chain.size() : m_db_blocks.size(); uint64_t coinstake_age = block_height - max_related_block_height - 1; @@ -5540,7 +5547,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt VARIANT_SWITCH_BEGIN(tx.signature); VARIANT_CASE(NLSAG_sig, signatures) signatures.s.clear(); - VARIANT_CASE(zarcanum_sig, s); + VARIANT_CASE_CONST(zarcanum_sig, s); //@#@ VARIANT_SWITCH_END(); @@ -6360,7 +6367,6 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, const crypto::hash& bl_id, const crypto::hash& input_tx_hash, size_t input_index, - const signature_v& input_sigs, uint64_t split_height, const alt_chain_type& alt_chain, const std::unordered_set& alt_chain_block_ids, @@ -6569,7 +6575,7 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, CHECK_AND_ASSERT_MES(it->second.first.vout.size() > out_n, false, "Internal error: out_n(" << out_n << ") >= it->second.vout.size()(" << it->second.first.vout.size() << ")"); VARIANT_SWITCH_BEGIN(it->second.first.vout[out_n]); - VARIANT_CASE(tx_out_bare, o) + VARIANT_CASE_CONST(tx_out_bare, o) { /* here we do validation against compatibility of input and output type @@ -6606,7 +6612,7 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, ASSERT_MES_AND_THROW("Unexpected out type for tx_in in altblock: " << out_target_v.type().name()); } } - VARIANT_CASE_TV(tx_out_zarcanum) + VARIANT_CASE_CONST(tx_out_zarcanum, toz) //@#@ VARIANT_SWITCH_END(); } @@ -6617,7 +6623,7 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, CHECK_AND_ASSERT_MES(p != nullptr && out_n < p->tx.vout.size(), false, "can't find output #" << out_n << " for tx " << tx_id << " referred by offset #" << pk_n); VARIANT_SWITCH_BEGIN(p->tx.vout[out_n]); - VARIANT_CASE(tx_out_bare, o) + VARIANT_CASE_CONST(tx_out_bare, o) { auto &t = o.target; @@ -6666,22 +6672,16 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, //CHECK_AND_ASSERT_MES(pk != null_pkey, false, "Can't determine output public key for offset " << pk_n << " in related tx: " << tx_id << ", out_n = " << out_n); pub_key_pointers.push_back(&pk); } - VARIANT_CASE_TV(tx_out_zarcanum) + VARIANT_CASE_CONST(tx_out_zarcanum, toz) //@#@ VARIANT_SWITCH_END(); } - VARIANT_SWITCH_BEGIN(input_sigs); - VARIANT_CASE(void_sig, v); - VARIANT_CASE(NLSAG_sig, signatures) - { - // do input checks (attachment_info, ring signature and extra signature, etc.) - r = check_input_signature(input_tx, input_index, input_to_key, input_tx_hash, signatures.s[input_index], pub_key_pointers); - CHECK_AND_ASSERT_MES(r, false, "to_key input validation failed"); - } - VARIANT_CASE(zarcanum_sig, s); - //@#@ - VARIANT_SWITCH_END(); + + // do input checks (attachment_info, ring signature and extra signature, etc.) + r = check_input_signature(input_tx, input_index, input_to_key, input_tx_hash, 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() return true; @@ -6788,7 +6788,7 @@ bool blockchain_storage::validate_alt_block_ms_input(const transaction& input_tx && input_tx.signature.type() == typeid(NLSAG_sig), false, "invalid ms input index: " << input_index << " or type"); const txin_multisig& input = boost::get(input_tx.vin[input_index]); - const std::vector& input_sigs = boost::get(input_tx.signature).s[input_index]; + //const std::vector& input_sigs = boost::get(input_tx.signature).s[input_index]; // check corresponding ms out in the main chain auto p = m_db_multisig_outs.get(input.multisig_out_id); if (p != nullptr) @@ -6803,7 +6803,7 @@ bool blockchain_storage::validate_alt_block_ms_input(const transaction& input_tx if (p_source_tx->m_keeper_block_height < split_height) { // cases g1, g2 - return check_ms_input(input_tx, input_index, input, input_tx_hash, input_sigs, p_source_tx->tx, p->out_no); + return check_ms_input(input_tx, input_index, input, input_tx_hash, p_source_tx->tx, p->out_no); } // p_source_tx is above split_height in main chain B, so it can't be a source for this input @@ -6838,7 +6838,7 @@ bool blockchain_storage::validate_alt_block_ms_input(const transaction& input_tx for (size_t out_n = 0; out_n < tx.vout.size(); ++out_n) { VARIANT_SWITCH_BEGIN(tx.vout[out_n]); - VARIANT_CASE(tx_out_bare, o) + VARIANT_CASE_CONST(tx_out_bare, o) const tx_out_bare& out = o; if (out.target.type() == typeid(txout_multisig)) { @@ -6847,10 +6847,10 @@ bool blockchain_storage::validate_alt_block_ms_input(const transaction& input_tx { // cases g3, g4, g5 output_found = true; - return check_ms_input(input_tx, input_index, input, input_tx_hash, input_sigs, tx, out_n); + return check_ms_input(input_tx, input_index, input, input_tx_hash, tx, out_n); } } - VARIANT_CASE_TV(tx_out_zarcanum) + VARIANT_CASE_CONST(tx_out_zarcanum, toz) //@#@ VARIANT_SWITCH_END(); } @@ -6903,7 +6903,7 @@ bool blockchain_storage::update_alt_out_indexes_for_tx_in_block(const transactio for (auto ov : tx.vout) { VARIANT_SWITCH_BEGIN(ov); - VARIANT_CASE(tx_out_bare, o) + VARIANT_CASE_CONST(tx_out_bare, o) if (o.target.type() == typeid(txout_to_key) || o.target.type() == typeid(txout_htlc)) { //LOG_PRINT_MAGENTA("ALT_OUT KEY ON H[" << abei.height << "] AMOUNT: " << o.amount, LOG_LEVEL_0); @@ -6925,7 +6925,7 @@ bool blockchain_storage::update_alt_out_indexes_for_tx_in_block(const transactio //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 } - VARIANT_CASE_TV(tx_out_zarcanum) + VARIANT_CASE_CONST(tx_out_zarcanum, toz) //@#@ VARIANT_SWITCH_END(); } @@ -6981,14 +6981,14 @@ bool blockchain_storage::validate_alt_block_txs(const block& b, const crypto::ha // check PoS block miner tx in a special way VARIANT_SWITCH_BEGIN(b.miner_tx.signature); - VARIANT_CASE(void_sig, v); - VARIANT_CASE(NLSAG_sig, signatures); + VARIANT_CASE_CONST(void_sig, v); + VARIANT_CASE_CONST(NLSAG_sig, signatures); { CHECK_AND_ASSERT_MES(signatures.s.size() == 1 && b.miner_tx.vin.size() == 2, false, "invalid PoS block's miner_tx, signatures size = " << signatures.s.size() << ", miner_tx.vin.size() = " << b.miner_tx.vin.size()); - r = validate_alt_block_input(b.miner_tx, collected_keyimages, alt_chain_tx_ids, id, get_block_hash(b), 1, signatures.s[0], split_height, alt_chain, alt_chain_block_ids, ki_lookup, &max_related_block_height); + r = validate_alt_block_input(b.miner_tx, collected_keyimages, alt_chain_tx_ids, id, get_block_hash(b), 1, split_height, alt_chain, alt_chain_block_ids, ki_lookup, &max_related_block_height); CHECK_AND_ASSERT_MES(r, false, "miner tx " << get_transaction_hash(b.miner_tx) << ": validation failed"); } - VARIANT_CASE(zarcanum_sig, s); + VARIANT_CASE_CONST(zarcanum_sig, s); //@#@ VARIANT_SWITCH_END(); @@ -7020,7 +7020,7 @@ bool blockchain_storage::validate_alt_block_txs(const block& b, const crypto::ha 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, alt_chain_tx_ids, id, tx_id, n, tx.signature, split_height, alt_chain, alt_chain_block_ids, ki_lookup); + r = validate_alt_block_input(tx, collected_keyimages, alt_chain_tx_ids, id, tx_id, n, split_height, alt_chain, alt_chain_block_ids, ki_lookup); CHECK_AND_ASSERT_MES(r, false, "tx " << tx_id << ", input #" << n << ": validation failed"); ki_lookup_time_total += ki_lookup; } diff --git a/src/currency_core/blockchain_storage.h b/src/currency_core/blockchain_storage.h index ef864b8a..e927398a 100644 --- a/src/currency_core/blockchain_storage.h +++ b/src/currency_core/blockchain_storage.h @@ -39,7 +39,7 @@ #include "dispatch_core_events.h" #include "bc_attachments_service_manager.h" #include "common/median_db_cache.h" - +#include "common/variant_helper.h" MARK_AS_POD_C11(crypto::key_image); @@ -286,25 +286,24 @@ namespace currency uint64_t get_aliases_count()const; uint64_t get_block_h_older_then(uint64_t timestamp) const; bool validate_tx_service_attachmens_in_services(const tx_service_attachment& a, size_t i, const transaction& tx)const; - bool check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const signature_v& sig, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase)const; - bool check_tx_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const signature_v& sig, uint64_t& max_related_block_height)const; - bool check_tx_input(const transaction& tx, size_t in_index, const txin_htlc& txin, const crypto::hash& tx_prefix_hash, const signature_v& sig, uint64_t& max_related_block_height)const; + bool check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase)const; + bool check_tx_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height)const; + bool check_tx_input(const transaction& tx, size_t in_index, const txin_htlc& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height)const; bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t& max_used_block_height)const; bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash) const; bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t& max_used_block_height, crypto::hash& max_used_block_id)const; - bool check_ms_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const signature_v& sig, const transaction& source_tx, size_t out_n) const; + bool check_ms_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const transaction& source_tx, size_t out_n) const; bool validate_tx_for_hardfork_specific_terms(const transaction& tx, const crypto::hash& tx_id, uint64_t block_height) const; bool validate_tx_for_hardfork_specific_terms(const transaction& tx, const crypto::hash& tx_id) const; bool get_output_keys_for_input_with_checks(const transaction& tx, const txin_v& verified_input, std::vector& output_keys, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase, scan_for_keys_context& scan_context) const; bool get_output_keys_for_input_with_checks(const transaction& tx, const txin_v& verified_input, std::vector& output_keys, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase) const; - bool check_input_signature(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, const std::vector& output_keys_ptrs) const; + bool check_input_signature(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& output_keys_ptrs) const; bool check_input_signature(const transaction& tx, size_t in_index, uint64_t in_amount, const crypto::key_image& k_image, const std::vector& in_etc_details, const crypto::hash& tx_prefix_hash, - const std::vector& sig, const std::vector& output_keys_ptrs) const; uint64_t get_current_comulative_blocksize_limit()const; @@ -597,7 +596,6 @@ namespace currency const crypto::hash& bl_id, const crypto::hash& input_tx_hash, size_t input_index, - const signature_v& input_sigs, //const std::vector& input_sigs, uint64_t split_height, const alt_chain_type& alt_chain, const std::unordered_set& alt_chain_block_ids, @@ -782,7 +780,7 @@ namespace currency */ VARIANT_SWITCH_BEGIN(tx_ptr->tx.vout[n]); - VARIANT_CASE(tx_out_bare, o) + VARIANT_CASE_CONST(tx_out_bare, o) { bool r = is_output_allowed_for_input(o.target, verified_input, get_current_blockchain_size() - tx_ptr->m_keeper_block_height); CHECK_AND_ASSERT_MES(r, false, "Input and output incompatible type"); @@ -821,21 +819,22 @@ namespace currency return false; } - TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output); - if (!vis.handle_output(tx_ptr->tx, validated_tx, tx_ptr->tx.vout[n], n)) + + if (!vis.handle_output(tx_ptr->tx, validated_tx, o, n)) { LOG_PRINT_L0("Failed to handle_output for output id = " << tx_id << ", no " << n); return false; } + TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output); } - VARIANT_CASE_TV(tx_out_zarcanum) + VARIANT_CASE_CONST(tx_out_zarcanum, oz) //@#@ + return false; VARIANT_CASE_THROW_ON_OTHER(); VARIANT_SWITCH_END(); - TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output); if (max_related_block_height < tx_ptr->m_keeper_block_height) max_related_block_height = tx_ptr->m_keeper_block_height; diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h index 8c24ac27..e5c022d7 100644 --- a/src/currency_core/currency_basic.h +++ b/src/currency_core/currency_basic.h @@ -659,16 +659,24 @@ namespace currency struct NLSAG_sig { std::vector > s; + + BEGIN_SERIALIZE_OBJECT() + FIELD(s) + END_SERIALIZE() }; struct zarcanum_sig { //TODO: + BEGIN_SERIALIZE_OBJECT() + END_SERIALIZE() }; struct void_sig { //TODO: + BEGIN_SERIALIZE_OBJECT() + END_SERIALIZE() }; typedef boost::variant signature_v; @@ -740,7 +748,7 @@ namespace currency vin.clear(); vout.clear(); extra.clear(); - signatures.clear(); + signature = void_sig(); attachment.clear(); } diff --git a/src/currency_core/currency_basic_backward_comp.inl b/src/currency_core/currency_basic_backward_comp.inl index fbd47181..9be0dc9c 100644 --- a/src/currency_core/currency_basic_backward_comp.inl +++ b/src/currency_core/currency_basic_backward_comp.inl @@ -75,7 +75,8 @@ bool transition_convert(const transaction_prefix_v1& from, transaction_prefix_cu } -class transaction_v1: + +class transaction_v1 { public: std::vector > signatures; //count signatures always the same as inputs count