From d328fae20dbba3a3063b63d87c6afcfdf8cf9a16 Mon Sep 17 00:00:00 2001 From: zexoverz Date: Tue, 15 Sep 2026 13:55:56 +0700 Subject: [PATCH] state: Widen the blob fee in the affordability check The blob part of the maximum transaction cost was multiplied in uint256, so with one blob and a max_fee_per_blob_gas of 2^239 the product wrapped to zero and the transaction passed the balance check it should have failed. Multiply into 512 bits like the gas part. Fixes #1480 --- test/state/state.cpp | 6 +----- test/unittests/state_transition_tx_test.cpp | 24 +++++++++++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/test/state/state.cpp b/test/state/state.cpp index 1046e295a5..1b46b6ebfb 100644 --- a/test/state/state.cpp +++ b/test/state/state.cpp @@ -537,11 +537,7 @@ std::variant validate_transaction( max_total_fee += tx.value; if (tx.type == Transaction::Type::blob) - { - const auto total_blob_gas = tx.blob_gas_used(); - // FIXME: Can overflow uint256. - max_total_fee += total_blob_gas * tx.max_blob_gas_price; - } + max_total_fee += umul(uint256{tx.blob_gas_used()}, tx.max_blob_gas_price); if (sender_acc.balance < max_total_fee) return make_error_code(INSUFFICIENT_ACCOUNT_FUNDS); diff --git a/test/unittests/state_transition_tx_test.cpp b/test/unittests/state_transition_tx_test.cpp index b0d9d6afe2..1677c4f366 100644 --- a/test/unittests/state_transition_tx_test.cpp +++ b/test/unittests/state_transition_tx_test.cpp @@ -111,6 +111,30 @@ TEST_F(state_transition, tx_blob_gas_price) expect.status = EVMC_SUCCESS; } +TEST_F(state_transition, invalid_tx_blob_max_fee_overflow) +{ + // With one blob, GAS_PER_BLOB * max_blob_gas_price is 2^17 * 2^239 = 2^256, which wraps to 0 + // in uint256 and would make the blob fee vanish from the affordability check. + rev = EVMC_CANCUN; + tx.type = Transaction::Type::blob; + tx.to = To; + tx.gas_limit = 25000; + tx.max_gas_price = block.base_fee; + tx.max_priority_gas_price = 0; + tx.nonce = 1; + tx.blob_hashes.emplace_back( + 0x0100000000000000000000000000000000000000000000000000000000000000_bytes32); + tx.max_blob_gas_price = intx::uint256{1} << 239; + + block.excess_blob_gas = 0; + block.blob_base_fee = 1; + block.blob_gas_used = 786432; + + pre[tx.sender].balance = tx.gas_limit * tx.max_gas_price; + + expect.tx_error = INSUFFICIENT_ACCOUNT_FUNDS; +} + TEST_F(state_transition, empty_coinbase_fee_0_sd) { rev = EVMC_SPURIOUS_DRAGON;