From 709d16eb753be332773d681a404406affd562577 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 27 Mar 2024 17:18:17 +0100 Subject: [PATCH] tx pool: asset operations basic validation on tx add --- src/currency_core/blockchain_storage.cpp | 72 ++++++++++--------- src/currency_core/blockchain_storage.h | 4 +- .../currency_format_utils_abstract.h | 21 ++++++ src/currency_core/tx_pool.cpp | 10 ++- 4 files changed, 71 insertions(+), 36 deletions(-) diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 6e781c68..500983fc 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -4012,7 +4012,7 @@ bool blockchain_storage::pop_asset_info(const crypto::public_key& asset_id) return true; } //------------------------------------------------------------------ -bool blockchain_storage::validate_ado_ownership(asset_op_verification_context& avc) +bool validate_ado_ownership(asset_op_verification_context& avc) { asset_operation_ownership_proof aoop = AUTO_VAL_INIT(aoop); bool r = get_type_in_variant_container(avc.tx.proofs, aoop); @@ -4024,32 +4024,23 @@ bool blockchain_storage::validate_ado_ownership(asset_op_verification_context& a return crypto::verify_schnorr_sig(avc.tx_id, owner_key, aoop.gss); } //------------------------------------------------------------------ -bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado) +bool blockchain_storage::validate_asset_operation_against_current_blochain_state(asset_op_verification_context& avc) const { CRITICAL_REGION_LOCAL(m_read_lock); - asset_op_verification_context avc = { tx, tx_id, ado }; + CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(avc.ado, &avc.asset_id_pt, &avc.asset_id), false, "get_or_calculate_asset_id failed"); + avc.asset_op_history = m_db_assets.find(avc.asset_id); + + const asset_descriptor_operation& ado = avc.ado; if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER) { - CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(avc.ado, &avc.asset_id_pt, &avc.asset_id), false, "get_or_calculate_asset_id failed"); - - avc.asset_op_history = m_db_assets.find(avc.asset_id); CHECK_AND_ASSERT_MES(!avc.asset_op_history, false, "asset with id " << avc.asset_id << " has already been registered"); - avc.amount_to_validate = ado.descriptor.current_supply; - CHECK_AND_ASSERT_MES(validate_asset_operation_amount_commitment(avc), false, "asset operation validation failed!"); - - assets_container::t_value_type local_asset_history = AUTO_VAL_INIT(local_asset_history); - local_asset_history.push_back(ado); - m_db_assets.set(avc.asset_id, local_asset_history); - LOG_PRINT_MAGENTA("[ASSET_REGISTERED]: " << print_money_brief(ado.descriptor.current_supply, ado.descriptor.decimal_point) << ", " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); + CHECK_AND_ASSERT_MES(validate_asset_operation_amount_commitment(avc), false, "validate_asset_operation_amount_commitment failed!"); } else { - CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(avc.ado, &avc.asset_id_pt, &avc.asset_id), false, "get_or_calculate_asset_id failed"); - avc.asset_op_history = m_db_assets.find(avc.asset_id); - CHECK_AND_ASSERT_MES(avc.asset_op_history && avc.asset_op_history->size(), false, "asset with id " << avc.asset_id << " has not been registered"); // check ownership permission if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE /*|| ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN*/) @@ -4092,25 +4083,40 @@ bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::has bool r = validate_asset_operation_amount_commitment(avc); CHECK_AND_ASSERT_MES(r, false, "Balance proof validation failed for asset_descriptor_operation"); } + } - assets_container::t_value_type local_asset_history = *avc.asset_op_history; - local_asset_history.push_back(ado); - m_db_assets.set(avc.asset_id, local_asset_history); + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado) +{ + CRITICAL_REGION_LOCAL(m_read_lock); - switch(ado.operation_type) - { - case ASSET_DESCRIPTOR_OPERATION_UPDATE: - LOG_PRINT_MAGENTA("[ASSET_UPDATED]: " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); - break; - case ASSET_DESCRIPTOR_OPERATION_EMIT: - LOG_PRINT_MAGENTA("[ASSET_EMITTED]: " << print_money_brief(avc.amount_to_validate, ado.descriptor.decimal_point) << ", " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); - break; - case ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN: - LOG_PRINT_MAGENTA("[ASSET_BURNT]: " << print_money_brief(avc.amount_to_validate, ado.descriptor.decimal_point) << ", " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); - break; - default: - LOG_ERROR("Unknown operation type: " << (int)ado.operation_type); - } + asset_op_verification_context avc = { tx, tx_id, ado }; + CHECK_AND_ASSERT_MES(validate_asset_operation_against_current_blochain_state(avc), false, "asset operation validation failed"); + + assets_container::t_value_type local_asset_history{}; + if (avc.asset_op_history) + local_asset_history = *avc.asset_op_history; + local_asset_history.push_back(ado); + m_db_assets.set(avc.asset_id, local_asset_history); + + switch(ado.operation_type) + { + case ASSET_DESCRIPTOR_OPERATION_REGISTER: + LOG_PRINT_MAGENTA("[ASSET_REGISTERED]: " << print_money_brief(ado.descriptor.current_supply, ado.descriptor.decimal_point) << ", " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); + break; + case ASSET_DESCRIPTOR_OPERATION_UPDATE: + LOG_PRINT_MAGENTA("[ASSET_UPDATED]: " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); + break; + case ASSET_DESCRIPTOR_OPERATION_EMIT: + LOG_PRINT_MAGENTA("[ASSET_EMITTED]: " << print_money_brief(avc.amount_to_validate, ado.descriptor.decimal_point) << ", " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); + break; + case ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN: + LOG_PRINT_MAGENTA("[ASSET_BURNT]: " << print_money_brief(avc.amount_to_validate, ado.descriptor.decimal_point) << ", " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); + break; + default: + LOG_ERROR("Unknown operation type: " << (int)ado.operation_type); } return true; diff --git a/src/currency_core/blockchain_storage.h b/src/currency_core/blockchain_storage.h index eb9c017a..c24e1104 100644 --- a/src/currency_core/blockchain_storage.h +++ b/src/currency_core/blockchain_storage.h @@ -375,6 +375,8 @@ namespace currency bool for_altchain, const alt_chain_type& alt_chain = alt_chain_type(), uint64_t split_height = 0)const; + bool validate_asset_operation_against_current_blochain_state(asset_op_verification_context& avc) const; + void set_core_runtime_config(const core_runtime_config& pc) const; const core_runtime_config& get_core_runtime_config()const; size_t get_current_sequence_factor(bool pos)const; @@ -494,6 +496,7 @@ namespace currency bool print_tx_outputs_lookup(const crypto::hash& tx_id) const; uint64_t get_last_x_block_height(bool pos)const; bool is_tx_spendtime_unlocked(uint64_t unlock_time)const; + private: //-------------- DB containers -------------- @@ -670,7 +673,6 @@ namespace currency bool unprocess_blockchain_tx_extra(const transaction& tx); bool process_blockchain_tx_attachments(const transaction& tx, uint64_t h, const crypto::hash& bl_id, uint64_t timestamp); bool unprocess_blockchain_tx_attachments(const transaction& tx, uint64_t h, uint64_t timestamp); - bool validate_ado_ownership(asset_op_verification_context& avc); bool pop_alias_info(const extra_alias_entry& ai); bool put_alias_info(const transaction& tx, extra_alias_entry& ai); bool pop_asset_info(const crypto::public_key& asset_id); diff --git a/src/currency_core/currency_format_utils_abstract.h b/src/currency_core/currency_format_utils_abstract.h index 11d051b9..416d955b 100644 --- a/src/currency_core/currency_format_utils_abstract.h +++ b/src/currency_core/currency_format_utils_abstract.h @@ -151,6 +151,27 @@ namespace currency return return_value_if_none_found; } //--------------------------------------------------------------- + // if cb returns false, stop immediately and return false + template + bool process_type_in_variant_container_and_make_sure_its_unique(const variant_container_t& av, callback_t& cb, bool return_value_if_none_found = true) + { + bool found = false; + for (auto& ai : av) + { + if (ai.type() == typeid(specific_type_t)) + { + if (found) + return false; // already have it, type in not unique + found = true; + if (!cb(boost::get(ai))) + return false; + } + } + if (found) + return true; + return return_value_if_none_found; + } + //--------------------------------------------------------------- // callback should return true to continue iterating through the container template bool handle_2_alternative_types_in_variant_container(const container_t& container, callback_t cb) diff --git a/src/currency_core/tx_pool.cpp b/src/currency_core/tx_pool.cpp index 998d4fed..a18e896d 100644 --- a/src/currency_core/tx_pool.cpp +++ b/src/currency_core/tx_pool.cpp @@ -224,13 +224,19 @@ namespace currency } TIME_MEASURE_FINISH_PD(check_inputs_time); - TIME_MEASURE_START_PD(check_post_hf4_balance); if (tx.version > TRANSACTION_VERSION_PRE_HF4) { + TIME_MEASURE_START_PD(check_post_hf4_balance); r = check_tx_balance(tx, id); CHECK_AND_ASSERT_MES_CUSTOM(r, false, { tvc.m_verification_failed = true; }, "post-HF4 tx: balance proof is invalid"); + TIME_MEASURE_FINISH_PD(check_post_hf4_balance); + + r = process_type_in_variant_container_and_make_sure_its_unique(tx.extra, [&](const asset_descriptor_operation& ado){ + asset_op_verification_context avc = { tx, id, ado }; + return m_blockchain.validate_asset_operation_against_current_blochain_state(avc); + }, true); + CHECK_AND_ASSERT_MES_CUSTOM(r, false, { tvc.m_verification_failed = true; }, "post-HF4 tx: asset operation is invalid"); } - TIME_MEASURE_FINISH_PD(check_post_hf4_balance); do_insert_transaction(tx, id, blob_size, kept_by_block, tx_fee, ch_inp_res ? max_used_block_id : null_hash, ch_inp_res ? max_used_block_height : 0);