diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index cc66cf69..2c788dd7 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -5617,7 +5617,11 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti if (var_is_after_hardfork_4_zone) { CHECK_AND_ASSERT_MES(tx.version > TRANSACTION_VERSION_PRE_HF4, false, "HF4: tx with version " << tx.version << " is not allowed"); - CHECK_AND_ASSERT_MES(tx.vout.size() >= CURRENCY_TX_MIN_ALLOWED_OUTS, false, "HF4: tx.vout has " << tx.vout.size() << " element(s), while required minimum is " << CURRENCY_TX_MIN_ALLOWED_OUTS); + + if (is_pos_miner_tx(tx)) + CHECK_AND_ASSERT_MES(tx.vout.size() == 1 || tx.vout.size() >= CURRENCY_TX_MIN_ALLOWED_OUTS, false, "HF4: tx.vout has " << tx.vout.size() << " element(s), while 1 or >= " << CURRENCY_TX_MIN_ALLOWED_OUTS << " is expected for a PoS miner tx"); + else + CHECK_AND_ASSERT_MES(tx.vout.size() >= CURRENCY_TX_MIN_ALLOWED_OUTS, false, "HF4: tx.vout has " << tx.vout.size() << " element(s), while required minimum is " << CURRENCY_TX_MIN_ALLOWED_OUTS); if(!validate_inputs_sorting(tx)) { diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index 0ff7c36f..83359fc5 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -387,8 +387,10 @@ namespace currency std::vector out_amounts; if (tx_version > TRANSACTION_VERSION_PRE_HF4) { - // randomly split into CURRENCY_TX_MIN_ALLOWED_OUTS outputs - decompose_amount_randomly(block_reward, [&](uint64_t a){ out_amounts.push_back(a); }, CURRENCY_TX_MIN_ALLOWED_OUTS); + // randomly split into CURRENCY_TX_MIN_ALLOWED_OUTS outputs for PoW block, or for PoS block only if the stakeholder address differs + // (otherwise for PoS miner tx there will be ONE output with amount = stake_amount + reward) + if (!pos || miner_address != stakeholder_address) + decompose_amount_randomly(block_reward, [&](uint64_t a){ out_amounts.push_back(a); }, CURRENCY_TX_MIN_ALLOWED_OUTS); } else { @@ -424,7 +426,8 @@ namespace currency uint64_t stake_lock_time = 0; if (pe.stake_unlock_time && pe.stake_unlock_time > height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW) stake_lock_time = pe.stake_unlock_time; - destinations.push_back(tx_destination_entry(pe.amount, stakeholder_address, stake_lock_time)); + uint64_t amount = destinations.empty() ? pe.amount + block_reward : pe.amount; // combine stake and reward into one output if no destinations were generated above + destinations.push_back(tx_destination_entry(amount, stakeholder_address, stake_lock_time)); destinations.back().flags |= tx_destination_entry_flags::tdef_explicit_native_asset_id; // don't use asset id blinding as it's obvious which asset it is }