diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 664d9e1c..d3e1bf05 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -7310,8 +7310,7 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, CRITICAL_REGION_LOCAL(m_read_lock); bool r = false; - if (p_max_related_block_height != nullptr) - *p_max_related_block_height = 0; + uint64_t max_related_block_height = 0; CHECK_AND_ASSERT_MES(input_index < input_tx.vin.size(), false, "invalid input index: " << input_index); @@ -7572,8 +7571,8 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, // case b4 (make sure source tx in the main chain is preceding split point, otherwise this referece is invalid) CHECK_AND_ASSERT_MES(p->m_keeper_block_height < split_height, false, "input offset #" << pk_n << " refers to main chain tx " << tx_id << " at height " << p->m_keeper_block_height << " while split height is " << split_height); - if (p_max_related_block_height != nullptr && *p_max_related_block_height < p->m_keeper_block_height) - *p_max_related_block_height = p->m_keeper_block_height; + if (max_related_block_height < p->m_keeper_block_height) + max_related_block_height = p->m_keeper_block_height; // TODO: consider checking p->tx for unlock time validity as it's checked in get_output_keys_for_input_with_checks() // make sure it was actually found @@ -7619,6 +7618,20 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, VARIANT_SWITCH_END(); + if (p_max_related_block_height != nullptr) + *p_max_related_block_height = max_related_block_height; + + uint64_t alt_bl_h = split_height + alt_chain.size() + 1; + if (m_core_runtime_config.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, alt_bl_h)) + { + if (alt_bl_h - max_related_block_height > CURRENCY_HF4_MANDATORY_MIN_COINAGE) + { + LOG_ERROR("Coinage rule broken(altblock): h = " << alt_bl_h << ", max_related_block_height=" << max_related_block_height << ", tx: " << input_tx_hash); + return false; + } + } + + // TODO: consider checking input_tx for valid extra attachment info as it's checked in check_tx_inputs() return true; } diff --git a/src/currency_core/blockchain_storage.h b/src/currency_core/blockchain_storage.h index b3cf29c6..0a584e5f 100644 --- a/src/currency_core/blockchain_storage.h +++ b/src/currency_core/blockchain_storage.h @@ -759,7 +759,7 @@ namespace currency TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_relative_to_absolute); TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop); size_t output_index = 0; - for(const txout_ref_v& o : absolute_offsets) + for (const txout_ref_v& o : absolute_offsets) { crypto::hash tx_id = null_hash; size_t n = 0; @@ -842,7 +842,7 @@ namespace currency } if (hf4) { - bool legit_output_key = validate_output_key_legit(scan_context.htlc_is_expired ? htlc_out.pkey_refund: htlc_out.pkey_redeem); + bool legit_output_key = validate_output_key_legit(scan_context.htlc_is_expired ? htlc_out.pkey_refund : htlc_out.pkey_redeem); CHECK_AND_ASSERT_MES(legit_output_key, false, "tx input ref #" << output_index << " violates public key restrictions: tx.version = " << tx_ptr->tx.version << ", outtk.key = " << static_cast(scan_context.htlc_is_expired ? htlc_out.pkey_refund : htlc_out.pkey_redeem)); } @@ -865,23 +865,23 @@ namespace currency } VARIANT_CASE_CONST(tx_out_zarcanum, out_zc) bool r = is_output_allowed_for_input(out_zc, verified_input); - CHECK_AND_ASSERT_MES(r, false, "Input and output are incompatible"); + CHECK_AND_ASSERT_MES(r, false, "Input and output are incompatible"); - r = is_mixattr_applicable_for_fake_outs_counter(tx_ptr->tx.version, out_zc.mix_attr, key_offsets.size() - 1, this->get_core_runtime_config()); - CHECK_AND_ASSERT_MES(r, false, "tx input ref #" << output_index << " violates mixin restrictions: tx.version = " << tx_ptr->tx.version << ", mix_attr = " << static_cast(out_zc.mix_attr) << ", key_offsets.size = " << key_offsets.size()); + r = is_mixattr_applicable_for_fake_outs_counter(tx_ptr->tx.version, out_zc.mix_attr, key_offsets.size() - 1, this->get_core_runtime_config()); + CHECK_AND_ASSERT_MES(r, false, "tx input ref #" << output_index << " violates mixin restrictions: tx.version = " << tx_ptr->tx.version << ", mix_attr = " << static_cast(out_zc.mix_attr) << ", key_offsets.size = " << key_offsets.size()); - bool legit_output_key = validate_output_key_legit(out_zc.stealth_address); - CHECK_AND_ASSERT_MES(legit_output_key, false, "tx input ref #" << output_index << " violates public key restrictions: tx.version = " << tx_ptr->tx.version << ", outtk.key = " << out_zc.stealth_address); + bool legit_output_key = validate_output_key_legit(out_zc.stealth_address); + CHECK_AND_ASSERT_MES(legit_output_key, false, "tx input ref #" << output_index << " violates public key restrictions: tx.version = " << tx_ptr->tx.version << ", outtk.key = " << out_zc.stealth_address); - TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output); - if (!vis.handle_output(tx_ptr->tx, validated_tx, out_zc, n)) - { - size_t verified_input_index = std::find(validated_tx.vin.begin(), validated_tx.vin.end(), verified_input) - validated_tx.vin.begin(); - LOG_PRINT_RED_L0("handle_output failed for output #" << n << " in " << tx_id << " referenced by input #" << verified_input_index << " in tx " << get_transaction_hash(validated_tx)); - return false; - } - TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output); + TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output); + if (!vis.handle_output(tx_ptr->tx, validated_tx, out_zc, n)) + { + size_t verified_input_index = std::find(validated_tx.vin.begin(), validated_tx.vin.end(), verified_input) - validated_tx.vin.begin(); + LOG_PRINT_RED_L0("handle_output failed for output #" << n << " in " << tx_id << " referenced by input #" << verified_input_index << " in tx " << get_transaction_hash(validated_tx)); + return false; + } + TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output); VARIANT_CASE_THROW_ON_OTHER(); VARIANT_SWITCH_END(); @@ -889,9 +889,22 @@ namespace currency if (max_related_block_height < tx_ptr->m_keeper_block_height) max_related_block_height = tx_ptr->m_keeper_block_height; - + ++output_index; } + + if (m_core_runtime_config.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, this->get_current_blockchain_size())) + { + //with hard fork 4 make it network rule to have at least 10 confirmations + + if (this->get_current_blockchain_size() - max_related_block_height > CURRENCY_HF4_MANDATORY_MIN_COINAGE) + { + LOG_ERROR("Coinage rule broken(mainblock): h = " << this->get_current_blockchain_size() << ", max_related_block_height=" << max_related_block_height << ", tx: " << get_transaction_hash(validated_tx)); + return false; + } + } + + TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop); return true; } diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h index b77791cb..db75b8c5 100644 --- a/src/currency_core/currency_config.h +++ b/src/currency_core/currency_config.h @@ -38,6 +38,7 @@ #define CURRENCY_DEFAULT_DECOY_SET_SIZE 10 #define CURRENCY_HF4_MANDATORY_DECOY_SET_SIZE 15 +#define CURRENCY_HF4_MANDATORY_MIN_COINAGE 10 #define CURRENT_BLOCK_MINOR_VERSION 0 #define CURRENCY_BLOCK_FUTURE_TIME_LIMIT 60*60*2 diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 6f05bd9c..67154320 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -47,7 +47,7 @@ #include "view_iface.h" #include "wallet2_base.h" -#define WALLET_DEFAULT_TX_SPENDABLE_AGE 10 +#define WALLET_DEFAULT_TX_SPENDABLE_AGE CURRENCY_HF4_MANDATORY_MIN_COINAGE #define WALLET_POS_MINT_CHECK_HEIGHT_INTERVAL 1