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;