diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 6946bca2..3c2e6f15 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -5220,7 +5220,16 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti if (var_is_after_hardfork_4_zone && !is_allowed_after_hardfork4(el)) return false; } - + + + if (var_is_after_hardfork_4_zone) + { + if(!validate_inputs_sorting(tx)) + { + return false; + } + } + return true; } diff --git a/src/currency_core/currency_format_utils_abstract.h b/src/currency_core/currency_format_utils_abstract.h index 1d99fb29..9e3a134d 100644 --- a/src/currency_core/currency_format_utils_abstract.h +++ b/src/currency_core/currency_format_utils_abstract.h @@ -148,6 +148,96 @@ namespace currency } } //--------------------------------------------------------------- + inline + const crypto::key_image & get_key_image_txin_v(const txin_v& in_v) + { + if (in_v.type() == typeid(txin_to_key)) + { + return boost::get(in_v).k_image; + } + else if (in_v.type() == typeid(txin_htlc)) + { + return boost::get(in_v).k_image; + } + else if (in_v.type() == typeid(txin_zc_input)) + { + return boost::get(in_v).k_image; + } + else + { + ASSERT_MES_AND_THROW("[get_to_key_input_from_txin_v] Wrong type " << in_v.type().name()); + } + } + + //, txin_htlc, txin_zc_input + bool compare_varian_by_types(const txin_multisig& left, typename txin_multisig& right) + { + return (left.multisig_out_id < right.multisig_out_id); + } + //--------------------------------------------------------------- + bool compare_varian_by_types(const txin_gen& left, typename txin_gen& right) + { + //actually this should never happen, should we leave it in case it happen in unit tests? @sowle + return (left.height < right.height); + } + //--------------------------------------------------------------- + template + bool compare_varian_by_types(const type_with_kimage_t& left, typename type_with_kimage_t& right) + { + return (left.k_image < right.k_image); + } + //--------------------------------------------------------------- + template + bool compare_varian_by_types(const t_type_left& left, const t_type_right& right) + { + if (typeid(t_type_left) == typeid(t_type_right)) + { + ASSERT_MES_AND_THROW("[compare_varian_by_types] Left and Right types matched type " << typeid(t_type_left).name()); + } + //@sowle should we use here variant index instead? (tags takes since it's ids something more "unchangebale", but we can reconsider) + return (variant_serialization_traits, typename t_type_left>::get_tag() < variant_serialization_traits, typename t_type_right>::get_tag()); + } + //--------------------------------------------------------------- + template + struct right_visitor : public boost::static_visitor + { + const t_type_left& m_rleft; + + right_visitor(const t_type_left& left) : m_rleft(left) + {} + + template + bool operator()(const t_type_right& right)const + { + return compare_varian_by_types(m_rleft, right); + } + }; + + struct left_visitor : public boost::static_visitor + { + const txin_v& m_rright; + + left_visitor(const txin_v& right) : m_rright(right) + {} + template + bool operator()(const t_type_left& left)const + { + return boost::apply_visitor(right_visitor(left), m_rright); + } + }; + //--------------------------------------------------------------- + bool less_txin_v(const txin_v& left, const txin_v& right) + { + //txin_gen, txin_to_key, txin_multisig, txin_htlc, txin_zc_input + if (left.type() != right.type()) + { + //predefined type hierarchy based on it's tags defined in currency_basic.h, call compare_varian_by_types via 2-level visitor + return boost::apply_visitor(left_visitor(right), left); + } + //compare + return true;//(left < right); + } + //--------------------------------------------------------------- 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) { diff --git a/src/currency_core/currency_format_utils_transactions.cpp b/src/currency_core/currency_format_utils_transactions.cpp index 46130401..33012294 100644 --- a/src/currency_core/currency_format_utils_transactions.cpp +++ b/src/currency_core/currency_format_utils_transactions.cpp @@ -275,14 +275,27 @@ namespace currency std::unordered_set ki; BOOST_FOREACH(const auto& in, tx.vin) { - if (in.type() == typeid(txin_to_key) || in.type() == typeid(txin_htlc)) + if (in.type() == typeid(txin_to_key) || in.type() == typeid(txin_htlc) || in.type() == typeid(txin_zc_input)) { - if (!ki.insert(get_to_key_input_from_txin_v(in).k_image).second) + if (!ki.insert(get_key_image_txin_v(in)).second) return false; } } return true; } - + //--------------------------------------------------------------- + bool validate_inputs_sorting(const transaction& tx) + { + size_t i = 0; + for(; i+1 < tx.vin.size(); i++) + { + //same less_txin_v() function should be used for sorting inputs during transacction creation + if (less_txin_v(tx.vin[i+1], tx.vin[i])) + { + return false; + } + } + return true; + } } \ No newline at end of file diff --git a/src/currency_core/currency_format_utils_transactions.h b/src/currency_core/currency_format_utils_transactions.h index af78a741..d678cc38 100644 --- a/src/currency_core/currency_format_utils_transactions.h +++ b/src/currency_core/currency_format_utils_transactions.h @@ -153,6 +153,7 @@ namespace currency blobdata tx_to_blob(const transaction& b); bool tx_to_blob(const transaction& b, blobdata& b_blob); bool read_keyimages_from_tx(const transaction& tx, std::list& kil); + bool validate_inputs_sorting(const transaction& tx); }