diff --git a/README.md b/README.md index 9471f9672f..8e84adc3d5 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Some clarifications were enabled without protocol releases: | [EIP-2681](https://eips.ethereum.org/EIPS/eip-2681) | 0 | | [EIP-3607](https://eips.ethereum.org/EIPS/eip-3607) | 0 | | [EIP-7523](https://eips.ethereum.org/EIPS/eip-7523) | 15537394 | -| [EIP-7610](https://github.com/ethereum/EIPs/pull/8161) | 0 | +| [EIP-7610](https://eips.ethereum.org/EIPS/eip-7610) | 0 | ## Execution Specification (work-in-progress) diff --git a/src/ethereum/arrow_glacier/transactions.py b/src/ethereum/arrow_glacier/transactions.py index bd857edcf6..751ed8fff7 100644 --- a/src/ethereum/arrow_glacier/transactions.py +++ b/src/ethereum/arrow_glacier/transactions.py @@ -13,7 +13,11 @@ from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover from ethereum.crypto.hash import Hash32, keccak256 -from ethereum.exceptions import InvalidSignatureError, InvalidTransaction +from ethereum.exceptions import ( + InsufficientTransactionGasError, + InvalidSignatureError, + NonceOverflowError, +) from .exceptions import TransactionTypeError from .fork_types import Address @@ -337,15 +341,17 @@ def validate_transaction(tx: Transaction) -> Uint: This function takes a transaction as a parameter and returns the intrinsic gas cost of the transaction after validation. It throws an - `InvalidTransaction` exception if the transaction is invalid. + `InsufficientTransactionGasError` exception if the transaction does not + provide enough gas to cover the intrinsic cost, and a `NonceOverflowError` + exception if the nonce is greater than `2**64 - 2`. [EIP-2681]: https://eips.ethereum.org/EIPS/eip-2681 """ intrinsic_gas = calculate_intrinsic_cost(tx) if intrinsic_gas > tx.gas: - raise InvalidTransaction("Insufficient gas") + raise InsufficientTransactionGasError("Insufficient gas") if U256(tx.nonce) >= U256(U64.MAX_VALUE): - raise InvalidTransaction("Nonce too high") + raise NonceOverflowError("Nonce too high") return intrinsic_gas diff --git a/src/ethereum/berlin/transactions.py b/src/ethereum/berlin/transactions.py index c1f3c990fc..4832858f53 100644 --- a/src/ethereum/berlin/transactions.py +++ b/src/ethereum/berlin/transactions.py @@ -13,7 +13,11 @@ from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover from ethereum.crypto.hash import Hash32, keccak256 -from ethereum.exceptions import InvalidSignatureError, InvalidTransaction +from ethereum.exceptions import ( + InsufficientTransactionGasError, + InvalidSignatureError, + NonceOverflowError, +) from .exceptions import TransactionTypeError from .fork_types import Address @@ -254,15 +258,17 @@ def validate_transaction(tx: Transaction) -> Uint: This function takes a transaction as a parameter and returns the intrinsic gas cost of the transaction after validation. It throws an - `InvalidTransaction` exception if the transaction is invalid. + `InsufficientTransactionGasError` exception if the transaction does not + provide enough gas to cover the intrinsic cost, and a `NonceOverflowError` + exception if the nonce is greater than `2**64 - 2`. [EIP-2681]: https://eips.ethereum.org/EIPS/eip-2681 """ intrinsic_gas = calculate_intrinsic_cost(tx) if intrinsic_gas > tx.gas: - raise InvalidTransaction("Insufficient gas") + raise InsufficientTransactionGasError("Insufficient gas") if U256(tx.nonce) >= U256(U64.MAX_VALUE): - raise InvalidTransaction("Nonce too high") + raise NonceOverflowError("Nonce too high") return intrinsic_gas diff --git a/src/ethereum/byzantium/transactions.py b/src/ethereum/byzantium/transactions.py index 5d84645388..7474ad74b6 100644 --- a/src/ethereum/byzantium/transactions.py +++ b/src/ethereum/byzantium/transactions.py @@ -12,7 +12,11 @@ from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover from ethereum.crypto.hash import Hash32, keccak256 -from ethereum.exceptions import InvalidSignatureError, InvalidTransaction +from ethereum.exceptions import ( + InsufficientTransactionGasError, + InvalidSignatureError, + NonceOverflowError, +) from .fork_types import Address @@ -110,15 +114,17 @@ def validate_transaction(tx: Transaction) -> Uint: This function takes a transaction as a parameter and returns the intrinsic gas cost of the transaction after validation. It throws an - `InvalidTransaction` exception if the transaction is invalid. + `InsufficientTransactionGasError` exception if the transaction does not + provide enough gas to cover the intrinsic cost, and a `NonceOverflowError` + exception if the nonce is greater than `2**64 - 2`. [EIP-2681]: https://eips.ethereum.org/EIPS/eip-2681 """ intrinsic_gas = calculate_intrinsic_cost(tx) if intrinsic_gas > tx.gas: - raise InvalidTransaction("Insufficient gas") + raise InsufficientTransactionGasError("Insufficient gas") if U256(tx.nonce) >= U256(U64.MAX_VALUE): - raise InvalidTransaction("Nonce too high") + raise NonceOverflowError("Nonce too high") return intrinsic_gas diff --git a/src/ethereum/cancun/exceptions.py b/src/ethereum/cancun/exceptions.py index 60b5f5f50f..5b46b80556 100644 --- a/src/ethereum/cancun/exceptions.py +++ b/src/ethereum/cancun/exceptions.py @@ -101,3 +101,9 @@ class PriorityFeeGreaterThanMaxFeeError(InvalidTransaction): """ The priority fee is greater than the maximum fee per gas. """ + + +class InitCodeTooLargeError(InvalidTransaction): + """ + The init code of the transaction is too large. + """ diff --git a/src/ethereum/cancun/transactions.py b/src/ethereum/cancun/transactions.py index 5c8be4708d..98a82bd21d 100644 --- a/src/ethereum/cancun/transactions.py +++ b/src/ethereum/cancun/transactions.py @@ -13,9 +13,13 @@ from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover from ethereum.crypto.hash import Hash32, keccak256 -from ethereum.exceptions import InvalidSignatureError, InvalidTransaction +from ethereum.exceptions import ( + InsufficientTransactionGasError, + InvalidSignatureError, + NonceOverflowError, +) -from .exceptions import TransactionTypeError +from .exceptions import InitCodeTooLargeError, TransactionTypeError from .fork_types import Address, VersionedHash TX_BASE_COST = Uint(21000) @@ -439,19 +443,23 @@ def validate_transaction(tx: Transaction) -> Uint: This function takes a transaction as a parameter and returns the intrinsic gas cost of the transaction after validation. It throws an - `InvalidTransaction` exception if the transaction is invalid. + `InsufficientTransactionGasError` exception if the transaction does not + provide enough gas to cover the intrinsic cost, and a `NonceOverflowError` + exception if the nonce is greater than `2**64 - 2`. It also raises an + `InitCodeTooLargeError` if the code size of a contract creation transaction + exceeds the maximum allowed size. [EIP-2681]: https://eips.ethereum.org/EIPS/eip-2681 """ - from .vm.interpreter import MAX_CODE_SIZE + from .vm.interpreter import MAX_INIT_CODE_SIZE intrinsic_gas = calculate_intrinsic_cost(tx) if intrinsic_gas > tx.gas: - raise InvalidTransaction("Insufficient gas") + raise InsufficientTransactionGasError("Insufficient gas") if U256(tx.nonce) >= U256(U64.MAX_VALUE): - raise InvalidTransaction("Nonce too high") - if tx.to == Bytes0(b"") and len(tx.data) > 2 * MAX_CODE_SIZE: - raise InvalidTransaction("Code size too large") + raise NonceOverflowError("Nonce too high") + if tx.to == Bytes0(b"") and len(tx.data) > MAX_INIT_CODE_SIZE: + raise InitCodeTooLargeError("Code size too large") return intrinsic_gas diff --git a/src/ethereum/cancun/vm/instructions/system.py b/src/ethereum/cancun/vm/instructions/system.py index eff607eede..39dad8bcf7 100644 --- a/src/ethereum/cancun/vm/instructions/system.py +++ b/src/ethereum/cancun/vm/instructions/system.py @@ -72,7 +72,7 @@ def generic_create( # This import causes a circular import error # if it's not moved inside this method from ...vm.interpreter import ( - MAX_CODE_SIZE, + MAX_INIT_CODE_SIZE, STACK_DEPTH_LIMIT, process_create_message, ) @@ -80,7 +80,7 @@ def generic_create( call_data = memory_read_bytes( evm.memory, memory_start_position, memory_size ) - if len(call_data) > 2 * MAX_CODE_SIZE: + if len(call_data) > MAX_INIT_CODE_SIZE: raise OutOfGasError create_message_gas = max_message_call_gas(Uint(evm.gas_left)) diff --git a/src/ethereum/cancun/vm/interpreter.py b/src/ethereum/cancun/vm/interpreter.py index 520baada21..b67812cb3e 100644 --- a/src/ethereum/cancun/vm/interpreter.py +++ b/src/ethereum/cancun/vm/interpreter.py @@ -62,6 +62,7 @@ STACK_DEPTH_LIMIT = Uint(1024) MAX_CODE_SIZE = 0x6000 +MAX_INIT_CODE_SIZE = 2 * MAX_CODE_SIZE @dataclass diff --git a/src/ethereum/constantinople/transactions.py b/src/ethereum/constantinople/transactions.py index 5d84645388..7474ad74b6 100644 --- a/src/ethereum/constantinople/transactions.py +++ b/src/ethereum/constantinople/transactions.py @@ -12,7 +12,11 @@ from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover from ethereum.crypto.hash import Hash32, keccak256 -from ethereum.exceptions import InvalidSignatureError, InvalidTransaction +from ethereum.exceptions import ( + InsufficientTransactionGasError, + InvalidSignatureError, + NonceOverflowError, +) from .fork_types import Address @@ -110,15 +114,17 @@ def validate_transaction(tx: Transaction) -> Uint: This function takes a transaction as a parameter and returns the intrinsic gas cost of the transaction after validation. It throws an - `InvalidTransaction` exception if the transaction is invalid. + `InsufficientTransactionGasError` exception if the transaction does not + provide enough gas to cover the intrinsic cost, and a `NonceOverflowError` + exception if the nonce is greater than `2**64 - 2`. [EIP-2681]: https://eips.ethereum.org/EIPS/eip-2681 """ intrinsic_gas = calculate_intrinsic_cost(tx) if intrinsic_gas > tx.gas: - raise InvalidTransaction("Insufficient gas") + raise InsufficientTransactionGasError("Insufficient gas") if U256(tx.nonce) >= U256(U64.MAX_VALUE): - raise InvalidTransaction("Nonce too high") + raise NonceOverflowError("Nonce too high") return intrinsic_gas diff --git a/src/ethereum/dao_fork/transactions.py b/src/ethereum/dao_fork/transactions.py index 777e9d8fdf..ca3591a720 100644 --- a/src/ethereum/dao_fork/transactions.py +++ b/src/ethereum/dao_fork/transactions.py @@ -12,7 +12,11 @@ from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover from ethereum.crypto.hash import Hash32, keccak256 -from ethereum.exceptions import InvalidSignatureError, InvalidTransaction +from ethereum.exceptions import ( + InsufficientTransactionGasError, + InvalidSignatureError, + NonceOverflowError, +) from .fork_types import Address @@ -110,15 +114,17 @@ def validate_transaction(tx: Transaction) -> Uint: This function takes a transaction as a parameter and returns the intrinsic gas cost of the transaction after validation. It throws an - `InvalidTransaction` exception if the transaction is invalid. + `InsufficientTransactionGasError` exception if the transaction does not + provide enough gas to cover the intrinsic cost, and a `NonceOverflowError` + exception if the nonce is greater than `2**64 - 2`. [EIP-2681]: https://eips.ethereum.org/EIPS/eip-2681 """ intrinsic_gas = calculate_intrinsic_cost(tx) if intrinsic_gas > tx.gas: - raise InvalidTransaction("Insufficient gas") + raise InsufficientTransactionGasError("Insufficient gas") if U256(tx.nonce) >= U256(U64.MAX_VALUE): - raise InvalidTransaction("Nonce too high") + raise NonceOverflowError("Nonce too high") return intrinsic_gas diff --git a/src/ethereum/exceptions.py b/src/ethereum/exceptions.py index b961b0e88a..7bff361467 100644 --- a/src/ethereum/exceptions.py +++ b/src/ethereum/exceptions.py @@ -60,3 +60,16 @@ class GasUsedExceedsLimitError(InvalidTransaction): Thrown when a transaction's gas usage exceeds the gas available in the block. """ + + +class InsufficientTransactionGasError(InvalidTransaction): + """ + Thrown when a transaction does not provide enough gas to cover its + intrinsic cost. + """ + + +class NonceOverflowError(InvalidTransaction): + """ + Thrown when a transaction's nonce is greater than `2**64 - 2`. + """ diff --git a/src/ethereum/frontier/transactions.py b/src/ethereum/frontier/transactions.py index b71d72b49e..4b4d20aa80 100644 --- a/src/ethereum/frontier/transactions.py +++ b/src/ethereum/frontier/transactions.py @@ -12,7 +12,11 @@ from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover from ethereum.crypto.hash import Hash32, keccak256 -from ethereum.exceptions import InvalidSignatureError, InvalidTransaction +from ethereum.exceptions import ( + InsufficientTransactionGasError, + InvalidSignatureError, + NonceOverflowError, +) from .fork_types import Address @@ -105,15 +109,17 @@ def validate_transaction(tx: Transaction) -> Uint: This function takes a transaction as a parameter and returns the intrinsic gas cost of the transaction after validation. It throws an - `InvalidTransaction` exception if the transaction is invalid. + `InsufficientTransactionGasError` exception if the transaction does not + provide enough gas to cover the intrinsic cost, and a `NonceOverflowError` + exception if the nonce is greater than `2**64 - 2`. [EIP-2681]: https://eips.ethereum.org/EIPS/eip-2681 """ intrinsic_gas = calculate_intrinsic_cost(tx) if intrinsic_gas > tx.gas: - raise InvalidTransaction("Insufficient gas") + raise InsufficientTransactionGasError("Insufficient gas") if U256(tx.nonce) >= U256(U64.MAX_VALUE): - raise InvalidTransaction("Nonce too high") + raise NonceOverflowError("Nonce too high") return intrinsic_gas diff --git a/src/ethereum/gray_glacier/transactions.py b/src/ethereum/gray_glacier/transactions.py index bd857edcf6..751ed8fff7 100644 --- a/src/ethereum/gray_glacier/transactions.py +++ b/src/ethereum/gray_glacier/transactions.py @@ -13,7 +13,11 @@ from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover from ethereum.crypto.hash import Hash32, keccak256 -from ethereum.exceptions import InvalidSignatureError, InvalidTransaction +from ethereum.exceptions import ( + InsufficientTransactionGasError, + InvalidSignatureError, + NonceOverflowError, +) from .exceptions import TransactionTypeError from .fork_types import Address @@ -337,15 +341,17 @@ def validate_transaction(tx: Transaction) -> Uint: This function takes a transaction as a parameter and returns the intrinsic gas cost of the transaction after validation. It throws an - `InvalidTransaction` exception if the transaction is invalid. + `InsufficientTransactionGasError` exception if the transaction does not + provide enough gas to cover the intrinsic cost, and a `NonceOverflowError` + exception if the nonce is greater than `2**64 - 2`. [EIP-2681]: https://eips.ethereum.org/EIPS/eip-2681 """ intrinsic_gas = calculate_intrinsic_cost(tx) if intrinsic_gas > tx.gas: - raise InvalidTransaction("Insufficient gas") + raise InsufficientTransactionGasError("Insufficient gas") if U256(tx.nonce) >= U256(U64.MAX_VALUE): - raise InvalidTransaction("Nonce too high") + raise NonceOverflowError("Nonce too high") return intrinsic_gas diff --git a/src/ethereum/homestead/transactions.py b/src/ethereum/homestead/transactions.py index 777e9d8fdf..ca3591a720 100644 --- a/src/ethereum/homestead/transactions.py +++ b/src/ethereum/homestead/transactions.py @@ -12,7 +12,11 @@ from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover from ethereum.crypto.hash import Hash32, keccak256 -from ethereum.exceptions import InvalidSignatureError, InvalidTransaction +from ethereum.exceptions import ( + InsufficientTransactionGasError, + InvalidSignatureError, + NonceOverflowError, +) from .fork_types import Address @@ -110,15 +114,17 @@ def validate_transaction(tx: Transaction) -> Uint: This function takes a transaction as a parameter and returns the intrinsic gas cost of the transaction after validation. It throws an - `InvalidTransaction` exception if the transaction is invalid. + `InsufficientTransactionGasError` exception if the transaction does not + provide enough gas to cover the intrinsic cost, and a `NonceOverflowError` + exception if the nonce is greater than `2**64 - 2`. [EIP-2681]: https://eips.ethereum.org/EIPS/eip-2681 """ intrinsic_gas = calculate_intrinsic_cost(tx) if intrinsic_gas > tx.gas: - raise InvalidTransaction("Insufficient gas") + raise InsufficientTransactionGasError("Insufficient gas") if U256(tx.nonce) >= U256(U64.MAX_VALUE): - raise InvalidTransaction("Nonce too high") + raise NonceOverflowError("Nonce too high") return intrinsic_gas diff --git a/src/ethereum/istanbul/transactions.py b/src/ethereum/istanbul/transactions.py index 81b1e51eee..46304b1fd6 100644 --- a/src/ethereum/istanbul/transactions.py +++ b/src/ethereum/istanbul/transactions.py @@ -12,7 +12,11 @@ from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover from ethereum.crypto.hash import Hash32, keccak256 -from ethereum.exceptions import InvalidSignatureError, InvalidTransaction +from ethereum.exceptions import ( + InsufficientTransactionGasError, + InvalidSignatureError, + NonceOverflowError, +) from .fork_types import Address @@ -110,15 +114,17 @@ def validate_transaction(tx: Transaction) -> Uint: This function takes a transaction as a parameter and returns the intrinsic gas cost of the transaction after validation. It throws an - `InvalidTransaction` exception if the transaction is invalid. + `InsufficientTransactionGasError` exception if the transaction does not + provide enough gas to cover the intrinsic cost, and a `NonceOverflowError` + exception if the nonce is greater than `2**64 - 2`. [EIP-2681]: https://eips.ethereum.org/EIPS/eip-2681 """ intrinsic_gas = calculate_intrinsic_cost(tx) if intrinsic_gas > tx.gas: - raise InvalidTransaction("Insufficient gas") + raise InsufficientTransactionGasError("Insufficient gas") if U256(tx.nonce) >= U256(U64.MAX_VALUE): - raise InvalidTransaction("Nonce too high") + raise NonceOverflowError("Nonce too high") return intrinsic_gas diff --git a/src/ethereum/london/transactions.py b/src/ethereum/london/transactions.py index bd857edcf6..751ed8fff7 100644 --- a/src/ethereum/london/transactions.py +++ b/src/ethereum/london/transactions.py @@ -13,7 +13,11 @@ from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover from ethereum.crypto.hash import Hash32, keccak256 -from ethereum.exceptions import InvalidSignatureError, InvalidTransaction +from ethereum.exceptions import ( + InsufficientTransactionGasError, + InvalidSignatureError, + NonceOverflowError, +) from .exceptions import TransactionTypeError from .fork_types import Address @@ -337,15 +341,17 @@ def validate_transaction(tx: Transaction) -> Uint: This function takes a transaction as a parameter and returns the intrinsic gas cost of the transaction after validation. It throws an - `InvalidTransaction` exception if the transaction is invalid. + `InsufficientTransactionGasError` exception if the transaction does not + provide enough gas to cover the intrinsic cost, and a `NonceOverflowError` + exception if the nonce is greater than `2**64 - 2`. [EIP-2681]: https://eips.ethereum.org/EIPS/eip-2681 """ intrinsic_gas = calculate_intrinsic_cost(tx) if intrinsic_gas > tx.gas: - raise InvalidTransaction("Insufficient gas") + raise InsufficientTransactionGasError("Insufficient gas") if U256(tx.nonce) >= U256(U64.MAX_VALUE): - raise InvalidTransaction("Nonce too high") + raise NonceOverflowError("Nonce too high") return intrinsic_gas diff --git a/src/ethereum/muir_glacier/transactions.py b/src/ethereum/muir_glacier/transactions.py index 81b1e51eee..46304b1fd6 100644 --- a/src/ethereum/muir_glacier/transactions.py +++ b/src/ethereum/muir_glacier/transactions.py @@ -12,7 +12,11 @@ from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover from ethereum.crypto.hash import Hash32, keccak256 -from ethereum.exceptions import InvalidSignatureError, InvalidTransaction +from ethereum.exceptions import ( + InsufficientTransactionGasError, + InvalidSignatureError, + NonceOverflowError, +) from .fork_types import Address @@ -110,15 +114,17 @@ def validate_transaction(tx: Transaction) -> Uint: This function takes a transaction as a parameter and returns the intrinsic gas cost of the transaction after validation. It throws an - `InvalidTransaction` exception if the transaction is invalid. + `InsufficientTransactionGasError` exception if the transaction does not + provide enough gas to cover the intrinsic cost, and a `NonceOverflowError` + exception if the nonce is greater than `2**64 - 2`. [EIP-2681]: https://eips.ethereum.org/EIPS/eip-2681 """ intrinsic_gas = calculate_intrinsic_cost(tx) if intrinsic_gas > tx.gas: - raise InvalidTransaction("Insufficient gas") + raise InsufficientTransactionGasError("Insufficient gas") if U256(tx.nonce) >= U256(U64.MAX_VALUE): - raise InvalidTransaction("Nonce too high") + raise NonceOverflowError("Nonce too high") return intrinsic_gas diff --git a/src/ethereum/osaka/exceptions.py b/src/ethereum/osaka/exceptions.py index 6a13bf2c85..e74948cb59 100644 --- a/src/ethereum/osaka/exceptions.py +++ b/src/ethereum/osaka/exceptions.py @@ -107,3 +107,19 @@ class EmptyAuthorizationListError(InvalidTransaction): """ The authorization list in the transaction is empty. """ + + +class InitCodeTooLargeError(InvalidTransaction): + """ + The init code of the transaction is too large. + """ + + +class TransactionGasLimitExceededError(InvalidTransaction): + """ + The transaction has specified a gas limit that is greater than the allowed + maximum. + + Note that this is _not_ the exception thrown when bytecode execution runs + out of gas. + """ diff --git a/src/ethereum/osaka/transactions.py b/src/ethereum/osaka/transactions.py index f345996b35..3dc3206d6b 100644 --- a/src/ethereum/osaka/transactions.py +++ b/src/ethereum/osaka/transactions.py @@ -13,9 +13,17 @@ from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover from ethereum.crypto.hash import Hash32, keccak256 -from ethereum.exceptions import InvalidSignatureError, InvalidTransaction +from ethereum.exceptions import ( + InsufficientTransactionGasError, + InvalidSignatureError, + NonceOverflowError, +) -from .exceptions import TransactionTypeError +from .exceptions import ( + InitCodeTooLargeError, + TransactionGasLimitExceededError, + TransactionTypeError, +) from .fork_types import Address, Authorization, VersionedHash TX_BASE_COST = Uint(21000) @@ -536,8 +544,11 @@ def validate_transaction(tx: Transaction) -> Tuple[Uint, Uint]: This function takes a transaction as a parameter and returns the intrinsic gas cost and the minimum calldata gas cost for the transaction after - validation. It throws an `InvalidTransaction` exception - if the transaction is invalid. + validation. It throws an `InsufficientTransactionGasError` exception if + the transaction does not provide enough gas to cover the intrinsic cost, + and a `NonceOverflowError` exception if the nonce is greater than + `2**64 - 2`. It also raises an `InitCodeTooLargeError` if the code size of + a contract creation transaction exceeds the maximum allowed size. [EIP-2681]: https://eips.ethereum.org/EIPS/eip-2681 [EIP-7623]: https://eips.ethereum.org/EIPS/eip-7623 @@ -546,13 +557,13 @@ def validate_transaction(tx: Transaction) -> Tuple[Uint, Uint]: intrinsic_gas, calldata_floor_gas_cost = calculate_intrinsic_cost(tx) if max(intrinsic_gas, calldata_floor_gas_cost) > tx.gas: - raise InvalidTransaction("Insufficient gas") + raise InsufficientTransactionGasError("Insufficient gas") if U256(tx.nonce) >= U256(U64.MAX_VALUE): - raise InvalidTransaction("Nonce too high") + raise NonceOverflowError("Nonce too high") if tx.to == Bytes0(b"") and len(tx.data) > MAX_INIT_CODE_SIZE: - raise InvalidTransaction("Code size too large") + raise InitCodeTooLargeError("Code size too large") if tx.gas > TX_MAX_GAS_LIMIT: - raise InvalidTransaction("Gas limit too high") + raise TransactionGasLimitExceededError("Gas limit too high") return intrinsic_gas, calldata_floor_gas_cost diff --git a/src/ethereum/paris/transactions.py b/src/ethereum/paris/transactions.py index bd857edcf6..751ed8fff7 100644 --- a/src/ethereum/paris/transactions.py +++ b/src/ethereum/paris/transactions.py @@ -13,7 +13,11 @@ from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover from ethereum.crypto.hash import Hash32, keccak256 -from ethereum.exceptions import InvalidSignatureError, InvalidTransaction +from ethereum.exceptions import ( + InsufficientTransactionGasError, + InvalidSignatureError, + NonceOverflowError, +) from .exceptions import TransactionTypeError from .fork_types import Address @@ -337,15 +341,17 @@ def validate_transaction(tx: Transaction) -> Uint: This function takes a transaction as a parameter and returns the intrinsic gas cost of the transaction after validation. It throws an - `InvalidTransaction` exception if the transaction is invalid. + `InsufficientTransactionGasError` exception if the transaction does not + provide enough gas to cover the intrinsic cost, and a `NonceOverflowError` + exception if the nonce is greater than `2**64 - 2`. [EIP-2681]: https://eips.ethereum.org/EIPS/eip-2681 """ intrinsic_gas = calculate_intrinsic_cost(tx) if intrinsic_gas > tx.gas: - raise InvalidTransaction("Insufficient gas") + raise InsufficientTransactionGasError("Insufficient gas") if U256(tx.nonce) >= U256(U64.MAX_VALUE): - raise InvalidTransaction("Nonce too high") + raise NonceOverflowError("Nonce too high") return intrinsic_gas diff --git a/src/ethereum/prague/exceptions.py b/src/ethereum/prague/exceptions.py index 6a13bf2c85..898d96beba 100644 --- a/src/ethereum/prague/exceptions.py +++ b/src/ethereum/prague/exceptions.py @@ -107,3 +107,9 @@ class EmptyAuthorizationListError(InvalidTransaction): """ The authorization list in the transaction is empty. """ + + +class InitCodeTooLargeError(InvalidTransaction): + """ + The init code of the transaction is too large. + """ diff --git a/src/ethereum/prague/transactions.py b/src/ethereum/prague/transactions.py index 7b3ea49710..b4023f1fea 100644 --- a/src/ethereum/prague/transactions.py +++ b/src/ethereum/prague/transactions.py @@ -13,9 +13,13 @@ from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover from ethereum.crypto.hash import Hash32, keccak256 -from ethereum.exceptions import InvalidSignatureError, InvalidTransaction +from ethereum.exceptions import ( + InsufficientTransactionGasError, + InvalidSignatureError, + NonceOverflowError, +) -from .exceptions import TransactionTypeError +from .exceptions import InitCodeTooLargeError, TransactionTypeError from .fork_types import Address, Authorization, VersionedHash TX_BASE_COST = Uint(21000) @@ -534,21 +538,24 @@ def validate_transaction(tx: Transaction) -> Tuple[Uint, Uint]: This function takes a transaction as a parameter and returns the intrinsic gas cost and the minimum calldata gas cost for the transaction after - validation. It throws an `InvalidTransaction` exception - if the transaction is invalid. + validation. It throws an `InsufficientTransactionGasError` exception if + the transaction does not provide enough gas to cover the intrinsic cost, + and a `NonceOverflowError` exception if the nonce is greater than + `2**64 - 2`. It also raises an `InitCodeTooLargeError` if the code size of + a contract creation transaction exceeds the maximum allowed size. [EIP-2681]: https://eips.ethereum.org/EIPS/eip-2681 [EIP-7623]: https://eips.ethereum.org/EIPS/eip-7623 """ - from .vm.interpreter import MAX_CODE_SIZE + from .vm.interpreter import MAX_INIT_CODE_SIZE intrinsic_gas, calldata_floor_gas_cost = calculate_intrinsic_cost(tx) if max(intrinsic_gas, calldata_floor_gas_cost) > tx.gas: - raise InvalidTransaction("Insufficient gas") + raise InsufficientTransactionGasError("Insufficient gas") if U256(tx.nonce) >= U256(U64.MAX_VALUE): - raise InvalidTransaction("Nonce too high") - if tx.to == Bytes0(b"") and len(tx.data) > 2 * MAX_CODE_SIZE: - raise InvalidTransaction("Code size too large") + raise NonceOverflowError("Nonce too high") + if tx.to == Bytes0(b"") and len(tx.data) > MAX_INIT_CODE_SIZE: + raise InitCodeTooLargeError("Code size too large") return intrinsic_gas, calldata_floor_gas_cost diff --git a/src/ethereum/prague/vm/instructions/system.py b/src/ethereum/prague/vm/instructions/system.py index aa3ae789bd..1ff9fe0481 100644 --- a/src/ethereum/prague/vm/instructions/system.py +++ b/src/ethereum/prague/vm/instructions/system.py @@ -73,7 +73,7 @@ def generic_create( # This import causes a circular import error # if it's not moved inside this method from ...vm.interpreter import ( - MAX_CODE_SIZE, + MAX_INIT_CODE_SIZE, STACK_DEPTH_LIMIT, process_create_message, ) @@ -81,7 +81,7 @@ def generic_create( call_data = memory_read_bytes( evm.memory, memory_start_position, memory_size ) - if len(call_data) > 2 * MAX_CODE_SIZE: + if len(call_data) > MAX_INIT_CODE_SIZE: raise OutOfGasError create_message_gas = max_message_call_gas(Uint(evm.gas_left)) diff --git a/src/ethereum/prague/vm/interpreter.py b/src/ethereum/prague/vm/interpreter.py index 33048686dc..342becba0e 100644 --- a/src/ethereum/prague/vm/interpreter.py +++ b/src/ethereum/prague/vm/interpreter.py @@ -64,6 +64,7 @@ STACK_DEPTH_LIMIT = Uint(1024) MAX_CODE_SIZE = 0x6000 +MAX_INIT_CODE_SIZE = 2 * MAX_CODE_SIZE @dataclass diff --git a/src/ethereum/shanghai/exceptions.py b/src/ethereum/shanghai/exceptions.py index 59968e94e2..8dc6c4d0e1 100644 --- a/src/ethereum/shanghai/exceptions.py +++ b/src/ethereum/shanghai/exceptions.py @@ -56,3 +56,9 @@ class PriorityFeeGreaterThanMaxFeeError(InvalidTransaction): """ The priority fee is greater than the maximum fee per gas. """ + + +class InitCodeTooLargeError(InvalidTransaction): + """ + The init code of the transaction is too large. + """ diff --git a/src/ethereum/shanghai/transactions.py b/src/ethereum/shanghai/transactions.py index 0347cb915d..1dff83bef2 100644 --- a/src/ethereum/shanghai/transactions.py +++ b/src/ethereum/shanghai/transactions.py @@ -13,9 +13,13 @@ from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover from ethereum.crypto.hash import Hash32, keccak256 -from ethereum.exceptions import InvalidSignatureError, InvalidTransaction +from ethereum.exceptions import ( + InsufficientTransactionGasError, + InvalidSignatureError, + NonceOverflowError, +) -from .exceptions import TransactionTypeError +from .exceptions import InitCodeTooLargeError, TransactionTypeError from .fork_types import Address TX_BASE_COST = Uint(21000) @@ -340,19 +344,23 @@ def validate_transaction(tx: Transaction) -> Uint: This function takes a transaction as a parameter and returns the intrinsic gas cost of the transaction after validation. It throws an - `InvalidTransaction` exception if the transaction is invalid. + `InsufficientTransactionGasError` exception if the transaction does not + provide enough gas to cover the intrinsic cost, and a `NonceOverflowError` + exception if the nonce is greater than `2**64 - 2`. It also raises an + `InitCodeTooLargeError` if the code size of a contract creation transaction + exceeds the maximum allowed size. [EIP-2681]: https://eips.ethereum.org/EIPS/eip-2681 """ - from .vm.interpreter import MAX_CODE_SIZE + from .vm.interpreter import MAX_INIT_CODE_SIZE intrinsic_gas = calculate_intrinsic_cost(tx) if intrinsic_gas > tx.gas: - raise InvalidTransaction("Insufficient gas") + raise InsufficientTransactionGasError("Insufficient gas") if U256(tx.nonce) >= U256(U64.MAX_VALUE): - raise InvalidTransaction("Nonce too high") - if tx.to == Bytes0(b"") and len(tx.data) > 2 * MAX_CODE_SIZE: - raise InvalidTransaction("Code size too large") + raise NonceOverflowError("Nonce too high") + if tx.to == Bytes0(b"") and len(tx.data) > MAX_INIT_CODE_SIZE: + raise InitCodeTooLargeError("Code size too large") return intrinsic_gas diff --git a/src/ethereum/shanghai/vm/instructions/system.py b/src/ethereum/shanghai/vm/instructions/system.py index 8d7e8b64f4..09805a28f5 100644 --- a/src/ethereum/shanghai/vm/instructions/system.py +++ b/src/ethereum/shanghai/vm/instructions/system.py @@ -71,7 +71,7 @@ def generic_create( # This import causes a circular import error # if it's not moved inside this method from ...vm.interpreter import ( - MAX_CODE_SIZE, + MAX_INIT_CODE_SIZE, STACK_DEPTH_LIMIT, process_create_message, ) @@ -79,7 +79,7 @@ def generic_create( call_data = memory_read_bytes( evm.memory, memory_start_position, memory_size ) - if len(call_data) > 2 * MAX_CODE_SIZE: + if len(call_data) > MAX_INIT_CODE_SIZE: raise OutOfGasError create_message_gas = max_message_call_gas(Uint(evm.gas_left)) diff --git a/src/ethereum/shanghai/vm/interpreter.py b/src/ethereum/shanghai/vm/interpreter.py index 4218e3b4ef..f962e6d1a1 100644 --- a/src/ethereum/shanghai/vm/interpreter.py +++ b/src/ethereum/shanghai/vm/interpreter.py @@ -62,6 +62,7 @@ STACK_DEPTH_LIMIT = Uint(1024) MAX_CODE_SIZE = 0x6000 +MAX_INIT_CODE_SIZE = 2 * MAX_CODE_SIZE @dataclass diff --git a/src/ethereum/spurious_dragon/transactions.py b/src/ethereum/spurious_dragon/transactions.py index 5d84645388..7474ad74b6 100644 --- a/src/ethereum/spurious_dragon/transactions.py +++ b/src/ethereum/spurious_dragon/transactions.py @@ -12,7 +12,11 @@ from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover from ethereum.crypto.hash import Hash32, keccak256 -from ethereum.exceptions import InvalidSignatureError, InvalidTransaction +from ethereum.exceptions import ( + InsufficientTransactionGasError, + InvalidSignatureError, + NonceOverflowError, +) from .fork_types import Address @@ -110,15 +114,17 @@ def validate_transaction(tx: Transaction) -> Uint: This function takes a transaction as a parameter and returns the intrinsic gas cost of the transaction after validation. It throws an - `InvalidTransaction` exception if the transaction is invalid. + `InsufficientTransactionGasError` exception if the transaction does not + provide enough gas to cover the intrinsic cost, and a `NonceOverflowError` + exception if the nonce is greater than `2**64 - 2`. [EIP-2681]: https://eips.ethereum.org/EIPS/eip-2681 """ intrinsic_gas = calculate_intrinsic_cost(tx) if intrinsic_gas > tx.gas: - raise InvalidTransaction("Insufficient gas") + raise InsufficientTransactionGasError("Insufficient gas") if U256(tx.nonce) >= U256(U64.MAX_VALUE): - raise InvalidTransaction("Nonce too high") + raise NonceOverflowError("Nonce too high") return intrinsic_gas diff --git a/src/ethereum/tangerine_whistle/transactions.py b/src/ethereum/tangerine_whistle/transactions.py index 777e9d8fdf..ca3591a720 100644 --- a/src/ethereum/tangerine_whistle/transactions.py +++ b/src/ethereum/tangerine_whistle/transactions.py @@ -12,7 +12,11 @@ from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover from ethereum.crypto.hash import Hash32, keccak256 -from ethereum.exceptions import InvalidSignatureError, InvalidTransaction +from ethereum.exceptions import ( + InsufficientTransactionGasError, + InvalidSignatureError, + NonceOverflowError, +) from .fork_types import Address @@ -110,15 +114,17 @@ def validate_transaction(tx: Transaction) -> Uint: This function takes a transaction as a parameter and returns the intrinsic gas cost of the transaction after validation. It throws an - `InvalidTransaction` exception if the transaction is invalid. + `InsufficientTransactionGasError` exception if the transaction does not + provide enough gas to cover the intrinsic cost, and a `NonceOverflowError` + exception if the nonce is greater than `2**64 - 2`. [EIP-2681]: https://eips.ethereum.org/EIPS/eip-2681 """ intrinsic_gas = calculate_intrinsic_cost(tx) if intrinsic_gas > tx.gas: - raise InvalidTransaction("Insufficient gas") + raise InsufficientTransactionGasError("Insufficient gas") if U256(tx.nonce) >= U256(U64.MAX_VALUE): - raise InvalidTransaction("Nonce too high") + raise NonceOverflowError("Nonce too high") return intrinsic_gas diff --git a/tests/berlin/test_transaction.py b/tests/berlin/test_transaction.py index ce5fc68e21..8e2422201c 100644 --- a/tests/berlin/test_transaction.py +++ b/tests/berlin/test_transaction.py @@ -7,7 +7,7 @@ LegacyTransaction, validate_transaction, ) -from ethereum.exceptions import InvalidTransaction +from ethereum.exceptions import NonceOverflowError from ethereum.utils.hexadecimal import hex_to_uint from tests.helpers import TEST_FIXTURES @@ -33,7 +33,7 @@ def test_high_nonce(test_file_high_nonce: str) -> None: tx = rlp.decode_to(LegacyTransaction, test["tx_rlp"]) - with pytest.raises(InvalidTransaction): + with pytest.raises(NonceOverflowError): validate_transaction(tx) diff --git a/tests/byzantium/test_transaction.py b/tests/byzantium/test_transaction.py index acb3e9070c..357ad15d2c 100644 --- a/tests/byzantium/test_transaction.py +++ b/tests/byzantium/test_transaction.py @@ -4,7 +4,7 @@ from ethereum_rlp import rlp from ethereum.byzantium.transactions import Transaction, validate_transaction -from ethereum.exceptions import InvalidTransaction +from ethereum.exceptions import NonceOverflowError from ethereum.utils.hexadecimal import hex_to_uint from tests.helpers import TEST_FIXTURES @@ -32,7 +32,7 @@ def test_high_nonce(test_file_high_nonce: str) -> None: tx = rlp.decode_to(Transaction, test["tx_rlp"]) - with pytest.raises(InvalidTransaction): + with pytest.raises(NonceOverflowError): validate_transaction(tx) diff --git a/tests/constantinople/test_transaction.py b/tests/constantinople/test_transaction.py index b11626d45d..4a302fb14b 100644 --- a/tests/constantinople/test_transaction.py +++ b/tests/constantinople/test_transaction.py @@ -7,7 +7,7 @@ Transaction, validate_transaction, ) -from ethereum.exceptions import InvalidTransaction +from ethereum.exceptions import NonceOverflowError from ethereum.utils.hexadecimal import hex_to_uint from tests.helpers import TEST_FIXTURES @@ -35,7 +35,7 @@ def test_high_nonce(test_file_high_nonce: str) -> None: tx = rlp.decode_to(Transaction, test["tx_rlp"]) - with pytest.raises(InvalidTransaction): + with pytest.raises(NonceOverflowError): validate_transaction(tx) diff --git a/tests/frontier/test_transaction.py b/tests/frontier/test_transaction.py index a2e72140d4..628b9c1787 100644 --- a/tests/frontier/test_transaction.py +++ b/tests/frontier/test_transaction.py @@ -3,7 +3,7 @@ import pytest from ethereum_rlp import rlp -from ethereum.exceptions import InvalidTransaction +from ethereum.exceptions import NonceOverflowError from ethereum.frontier.transactions import Transaction, validate_transaction from ethereum.utils.hexadecimal import hex_to_uint from tests.helpers import TEST_FIXTURES @@ -30,7 +30,7 @@ def test_high_nonce(test_file_high_nonce: str) -> None: tx = rlp.decode_to(Transaction, test["tx_rlp"]) - with pytest.raises(InvalidTransaction): + with pytest.raises(NonceOverflowError): validate_transaction(tx) diff --git a/tests/homestead/test_transaction.py b/tests/homestead/test_transaction.py index 7562afa3d5..095f3a2331 100644 --- a/tests/homestead/test_transaction.py +++ b/tests/homestead/test_transaction.py @@ -3,7 +3,7 @@ import pytest from ethereum_rlp import rlp -from ethereum.exceptions import InvalidTransaction +from ethereum.exceptions import NonceOverflowError from ethereum.homestead.transactions import Transaction, validate_transaction from ethereum.utils.hexadecimal import hex_to_uint from tests.helpers import TEST_FIXTURES @@ -32,7 +32,7 @@ def test_high_nonce(test_file_high_nonce: str) -> None: tx = rlp.decode_to(Transaction, test["tx_rlp"]) - with pytest.raises(InvalidTransaction): + with pytest.raises(NonceOverflowError): validate_transaction(tx) diff --git a/tests/istanbul/test_transaction.py b/tests/istanbul/test_transaction.py index 37a096445d..9b9bc6ce80 100644 --- a/tests/istanbul/test_transaction.py +++ b/tests/istanbul/test_transaction.py @@ -3,7 +3,7 @@ import pytest from ethereum_rlp import rlp -from ethereum.exceptions import InvalidTransaction +from ethereum.exceptions import NonceOverflowError from ethereum.istanbul.transactions import Transaction, validate_transaction from ethereum.utils.hexadecimal import hex_to_uint from tests.helpers import TEST_FIXTURES @@ -30,7 +30,7 @@ def test_high_nonce(test_file_high_nonce: str) -> None: tx = rlp.decode_to(Transaction, test["tx_rlp"]) - with pytest.raises(InvalidTransaction): + with pytest.raises(NonceOverflowError): validate_transaction(tx) diff --git a/tests/london/test_transaction.py b/tests/london/test_transaction.py index 5925474afe..5b47ee2b22 100644 --- a/tests/london/test_transaction.py +++ b/tests/london/test_transaction.py @@ -3,7 +3,7 @@ import pytest from ethereum_rlp import rlp -from ethereum.exceptions import InvalidTransaction +from ethereum.exceptions import NonceOverflowError from ethereum.london.transactions import ( LegacyTransaction, validate_transaction, @@ -33,7 +33,7 @@ def test_high_nonce(test_file_high_nonce: str) -> None: tx = rlp.decode_to(LegacyTransaction, test["tx_rlp"]) - with pytest.raises(InvalidTransaction): + with pytest.raises(NonceOverflowError): validate_transaction(tx) diff --git a/tests/spurious_dragon/test_transaction.py b/tests/spurious_dragon/test_transaction.py index 5e25d340ac..07773db878 100644 --- a/tests/spurious_dragon/test_transaction.py +++ b/tests/spurious_dragon/test_transaction.py @@ -3,7 +3,7 @@ import pytest from ethereum_rlp import rlp -from ethereum.exceptions import InvalidTransaction +from ethereum.exceptions import NonceOverflowError from ethereum.spurious_dragon.transactions import ( Transaction, validate_transaction, @@ -35,7 +35,7 @@ def test_high_nonce(test_file_high_nonce: str) -> None: tx = rlp.decode_to(Transaction, test["tx_rlp"]) - with pytest.raises(InvalidTransaction): + with pytest.raises(NonceOverflowError): validate_transaction(tx) diff --git a/tests/tangerine_whistle/test_transaction.py b/tests/tangerine_whistle/test_transaction.py index 455630e8a3..548dba328f 100644 --- a/tests/tangerine_whistle/test_transaction.py +++ b/tests/tangerine_whistle/test_transaction.py @@ -3,7 +3,7 @@ import pytest from ethereum_rlp import rlp -from ethereum.exceptions import InvalidTransaction +from ethereum.exceptions import NonceOverflowError from ethereum.tangerine_whistle.transactions import ( Transaction, validate_transaction, @@ -35,7 +35,7 @@ def test_high_nonce(test_file_high_nonce: str) -> None: tx = rlp.decode_to(Transaction, test["tx_rlp"]) - with pytest.raises(InvalidTransaction): + with pytest.raises(NonceOverflowError): validate_transaction(tx)