diff --git a/src/ethereum/prague/blobs.py b/src/ethereum/prague/blobs.py new file mode 100644 index 0000000000..78d78615fc --- /dev/null +++ b/src/ethereum/prague/blobs.py @@ -0,0 +1,119 @@ +""" +Blob Gas Calculations +^^^^^^^^^^^^^^^^^^^^^ + +.. contents:: Table of Contents + :backlinks: none + :local: + +Introduction +------------ + +Blob gas calculations for blocks and transactions. +""" + +from ethereum_types.numeric import U64, Uint + +from ..utils.numeric import taylor_exponential +from .blocks import Header +from .transactions import BlobTransaction, Transaction + +# Blob gas constants +TARGET_BLOB_GAS_PER_BLOCK = U64(786432) +GAS_PER_BLOB = U64(2**17) +MIN_BLOB_GASPRICE = Uint(1) +BLOB_BASE_FEE_UPDATE_FRACTION = Uint(5007716) +MAX_BLOB_GAS_PER_BLOCK = U64(786432) + + +def calculate_excess_blob_gas(parent_header: Header) -> U64: + """ + Calculated the excess blob gas for the current block based + on the gas used in the parent block. + + Parameters + ---------- + parent_header : + The parent block of the current block. + + Returns + ------- + excess_blob_gas: `ethereum.base_types.U64` + The excess blob gas for the current block. + """ + # At the fork block, these are defined as zero. + excess_blob_gas = U64(0) + blob_gas_used = U64(0) + + if isinstance(parent_header, Header): + # After the fork block, read them from the parent header. + excess_blob_gas = parent_header.excess_blob_gas + blob_gas_used = parent_header.blob_gas_used + + parent_blob_gas = excess_blob_gas + blob_gas_used + if parent_blob_gas < TARGET_BLOB_GAS_PER_BLOCK: + return U64(0) + else: + return parent_blob_gas - TARGET_BLOB_GAS_PER_BLOCK + + +def calculate_total_blob_gas(tx: Transaction) -> U64: + """ + Calculate the total blob gas for a transaction. + + Parameters + ---------- + tx : + The transaction for which the blob gas is to be calculated. + + Returns + ------- + total_blob_gas: `ethereum.base_types.Uint` + The total blob gas for the transaction. + """ + if isinstance(tx, BlobTransaction): + return GAS_PER_BLOB * U64(len(tx.blob_versioned_hashes)) + else: + return U64(0) + + +def calculate_blob_gas_price(excess_blob_gas: U64) -> Uint: + """ + Calculate the blob gasprice for a block. + + Parameters + ---------- + excess_blob_gas : + The excess blob gas for the block. + + Returns + ------- + blob_gasprice: `Uint` + The blob gasprice. + """ + return taylor_exponential( + MIN_BLOB_GASPRICE, + Uint(excess_blob_gas), + BLOB_BASE_FEE_UPDATE_FRACTION, + ) + + +def calculate_data_fee(excess_blob_gas: U64, tx: Transaction) -> Uint: + """ + Calculate the blob data fee for a transaction. + + Parameters + ---------- + excess_blob_gas : + The excess_blob_gas for the execution. + tx : + The transaction for which the blob data fee is to be calculated. + + Returns + ------- + data_fee: `Uint` + The blob data fee. + """ + return Uint(calculate_total_blob_gas(tx)) * calculate_blob_gas_price( + excess_blob_gas + ) diff --git a/src/ethereum/prague/fork.py b/src/ethereum/prague/fork.py index 70f5578dd8..40d62a6a0f 100644 --- a/src/ethereum/prague/fork.py +++ b/src/ethereum/prague/fork.py @@ -27,6 +27,13 @@ ) from . import vm +from .blobs import ( + MAX_BLOB_GAS_PER_BLOCK, + calculate_blob_gas_price, + calculate_data_fee, + calculate_excess_blob_gas, + calculate_total_blob_gas, +) from .blocks import Block, Header, Log, Receipt, Withdrawal, encode_receipt from .bloom import logs_bloom from .fork_types import Account, Address, Authorization, VersionedHash @@ -66,12 +73,6 @@ from .utils.message import prepare_message from .vm import Message from .vm.eoa_delegation import is_valid_delegation -from .vm.gas import ( - calculate_blob_gas_price, - calculate_data_fee, - calculate_excess_blob_gas, - calculate_total_blob_gas, -) from .vm.interpreter import MessageCallOutput, process_message_call BASE_FEE_MAX_CHANGE_DENOMINATOR = Uint(8) @@ -84,7 +85,6 @@ "0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02" ) SYSTEM_TRANSACTION_GAS = Uint(30000000) -MAX_BLOB_GAS_PER_BLOCK = U64(1179648) VERSIONED_HASH_VERSION_KZG = b"\x01" WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS = hex_to_address( diff --git a/src/ethereum/prague/vm/gas.py b/src/ethereum/prague/vm/gas.py index b3a96ef970..798d1b73a7 100644 --- a/src/ethereum/prague/vm/gas.py +++ b/src/ethereum/prague/vm/gas.py @@ -14,13 +14,11 @@ from dataclasses import dataclass from typing import List, Tuple -from ethereum_types.numeric import U64, U256, Uint +from ethereum_types.numeric import U256, Uint from ethereum.trace import GasAndRefund, evm_trace -from ethereum.utils.numeric import ceil32, taylor_exponential +from ethereum.utils.numeric import ceil32 -from ..blocks import Header -from ..transactions import BlobTransaction, Transaction from . import Evm from .exceptions import OutOfGasError @@ -68,11 +66,6 @@ GAS_BLOBHASH_OPCODE = Uint(3) GAS_POINT_EVALUATION = Uint(50000) -TARGET_BLOB_GAS_PER_BLOCK = U64(786432) -GAS_PER_BLOB = U64(2**17) -MIN_BLOB_GASPRICE = Uint(1) -BLOB_BASE_FEE_UPDATE_FRACTION = Uint(5007716) - GAS_BLS_G1_ADD = Uint(375) GAS_BLS_G1_MUL = Uint(12000) GAS_BLS_G1_MAP = Uint(5500) @@ -275,96 +268,3 @@ def init_code_cost(init_code_length: Uint) -> Uint: The gas to be charged for the init code. """ return GAS_INIT_CODE_WORD_COST * ceil32(init_code_length) // Uint(32) - - -def calculate_excess_blob_gas(parent_header: Header) -> U64: - """ - Calculated the excess blob gas for the current block based - on the gas used in the parent block. - - Parameters - ---------- - parent_header : - The parent block of the current block. - - Returns - ------- - excess_blob_gas: `ethereum.base_types.U64` - The excess blob gas for the current block. - """ - # At the fork block, these are defined as zero. - excess_blob_gas = U64(0) - blob_gas_used = U64(0) - - if isinstance(parent_header, Header): - # After the fork block, read them from the parent header. - excess_blob_gas = parent_header.excess_blob_gas - blob_gas_used = parent_header.blob_gas_used - - parent_blob_gas = excess_blob_gas + blob_gas_used - if parent_blob_gas < TARGET_BLOB_GAS_PER_BLOCK: - return U64(0) - else: - return parent_blob_gas - TARGET_BLOB_GAS_PER_BLOCK - - -def calculate_total_blob_gas(tx: Transaction) -> U64: - """ - Calculate the total blob gas for a transaction. - - Parameters - ---------- - tx : - The transaction for which the blob gas is to be calculated. - - Returns - ------- - total_blob_gas: `ethereum.base_types.Uint` - The total blob gas for the transaction. - """ - if isinstance(tx, BlobTransaction): - return GAS_PER_BLOB * U64(len(tx.blob_versioned_hashes)) - else: - return U64(0) - - -def calculate_blob_gas_price(excess_blob_gas: U64) -> Uint: - """ - Calculate the blob gasprice for a block. - - Parameters - ---------- - excess_blob_gas : - The excess blob gas for the block. - - Returns - ------- - blob_gasprice: `Uint` - The blob gasprice. - """ - return taylor_exponential( - MIN_BLOB_GASPRICE, - Uint(excess_blob_gas), - BLOB_BASE_FEE_UPDATE_FRACTION, - ) - - -def calculate_data_fee(excess_blob_gas: U64, tx: Transaction) -> Uint: - """ - Calculate the blob data fee for a transaction. - - Parameters - ---------- - excess_blob_gas : - The excess_blob_gas for the execution. - tx : - The transaction for which the blob data fee is to be calculated. - - Returns - ------- - data_fee: `Uint` - The blob data fee. - """ - return Uint(calculate_total_blob_gas(tx)) * calculate_blob_gas_price( - excess_blob_gas - ) diff --git a/src/ethereum/prague/vm/instructions/environment.py b/src/ethereum/prague/vm/instructions/environment.py index 5ddd12dac8..7dc5fff686 100644 --- a/src/ethereum/prague/vm/instructions/environment.py +++ b/src/ethereum/prague/vm/instructions/environment.py @@ -18,6 +18,7 @@ from ethereum.crypto.hash import keccak256 from ethereum.utils.numeric import ceil32 +from ...blobs import calculate_blob_gas_price from ...fork_types import EMPTY_ACCOUNT from ...state import get_account from ...utils.address import to_address @@ -33,7 +34,6 @@ GAS_RETURN_DATA_COPY, GAS_VERY_LOW, GAS_WARM_ACCESS, - calculate_blob_gas_price, calculate_gas_extend_memory, charge_gas, ) @@ -460,7 +460,7 @@ def returndatacopy(evm: Evm) -> None: def extcodehash(evm: Evm) -> None: """ - Returns the keccak256 hash of a contract’s bytecode + Returns the keccak256 hash of a contracts bytecode Parameters ---------- evm :