diff --git a/zebra-consensus/src/block/check.rs b/zebra-consensus/src/block/check.rs index 2e27bc42aa8..45c8efb467c 100644 --- a/zebra-consensus/src/block/check.rs +++ b/zebra-consensus/src/block/check.rs @@ -269,7 +269,16 @@ pub fn miner_fees_are_valid( let right = (block_subsidy + block_miner_fees - expected_deferred_amount) .map_err(|_| SubsidyError::SumOverflow)?; - if left > right { + // TODO: Add link to exact coinbase balance ZIP + let should_allow_unclaimed_subsidy = + NetworkUpgrade::current(network, height) < NetworkUpgrade::Nu6; + let is_invalid_miner_fee = if should_allow_unclaimed_subsidy { + left > right + } else { + left != right + }; + + if is_invalid_miner_fee { Err(SubsidyError::InvalidMinerFees)?; } diff --git a/zebrad/tests/acceptance.rs b/zebrad/tests/acceptance.rs index 03e6f97c2f1..630ec38cc63 100644 --- a/zebrad/tests/acceptance.rs +++ b/zebrad/tests/acceptance.rs @@ -3467,6 +3467,49 @@ async fn nu6_funding_streams() -> Result<()> { "invalid block with excessive coinbase output value should be rejected" ); + // Use an invalid coinbase transaction (with an output value less than than the `block_subsidy + miner_fees - expected_lockbox_funding_stream`) + let network = base_network_params + .clone() + .with_post_nu6_funding_streams(ConfiguredFundingStreams { + height_range: Some(Height(1)..Height(100)), + recipients: make_configured_recipients_with_lockbox_numerator(20), + }) + .to_network(); + + let (coinbase_txn, default_roots) = generate_coinbase_and_roots( + &network, + Height(block_template.height), + &miner_address, + &[], + history_tree.clone(), + true, + vec![], + ); + + let block_template = GetBlockTemplate { + coinbase_txn, + block_commitments_hash: default_roots.block_commitments_hash, + light_client_root_hash: default_roots.block_commitments_hash, + final_sapling_root_hash: default_roots.block_commitments_hash, + default_roots, + ..block_template + }; + + let proposal_block = proposal_block_from_template(&block_template, None, NetworkUpgrade::Nu6)?; + + // Submit the invalid block with an excessive coinbase input value + let submit_block_response = get_block_template_rpc_impl + .submit_block(HexData(proposal_block.zcash_serialize_to_vec()?), None) + .await?; + + tracing::info!(?submit_block_response, "submitted invalid block"); + + assert_eq!( + submit_block_response, + submit_block::Response::ErrorResponse(submit_block::ErrorResponse::Rejected), + "invalid block with insufficient coinbase output value should be rejected" + ); + // Check that the original block template can be submitted successfully let proposal_block = proposal_block_from_template(&valid_original_block_template, None, NetworkUpgrade::Nu6)?;