Skip to content

Commit

Permalink
Merge pull request #139 from marioevz/excess-data-gas-calc-spec-update
Browse files Browse the repository at this point in the history
tests/4844: `excessDataGas` and `dataGasUsed` spec update
  • Loading branch information
spencer-tb authored Jun 14, 2023
2 parents 7d5e395 + 18b555a commit 5ac602e
Show file tree
Hide file tree
Showing 15 changed files with 701 additions and 416 deletions.
10 changes: 9 additions & 1 deletion src/ethereum_test_forks/base_fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def name(cls) -> str:
"""
To be implemented by the fork base class.
"""
pass
return ""

def __repr__(cls) -> str:
"""
Expand Down Expand Up @@ -70,6 +70,14 @@ def header_excess_data_gas_required(cls, block_number: int, timestamp: int) -> b
"""
pass

@classmethod
@abstractmethod
def header_data_gas_used_required(cls, block_number: int, timestamp: int) -> bool:
"""
Returns true if the header must contain data gas used
"""
pass

@classmethod
@abstractmethod
def get_reward(cls, block_number: int, timestamp: int) -> int:
Expand Down
14 changes: 14 additions & 0 deletions src/ethereum_test_forks/forks/forks.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ def header_excess_data_gas_required(cls, block_number: int, timestamp: int) -> b
"""
return False

@classmethod
def header_data_gas_used_required(cls, block_number: int, timestamp: int) -> bool:
"""
At genesis, header must not contain data gas used
"""
return False

@classmethod
def get_reward(cls, block_number: int, timestamp: int) -> int:
"""
Expand Down Expand Up @@ -212,3 +219,10 @@ def header_excess_data_gas_required(cls, block_number: int, timestamp: int) -> b
Excess data gas is required starting from Cancun.
"""
return True

@classmethod
def header_data_gas_used_required(cls, block_number: int, timestamp: int) -> bool:
"""
Data gas used is required starting from Cancun.
"""
return True
26 changes: 24 additions & 2 deletions src/ethereum_test_tools/common/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,8 +557,10 @@ class Environment:
parent_gas_limit: Optional[int] = None
parent_ommers_hash: Optional[str] = None
withdrawals: Optional[List[Withdrawal]] = None
excess_data_gas: Optional[int] = None
parent_data_gas_used: Optional[int] = None
parent_excess_data_gas: Optional[int] = None
excess_data_gas: Optional[int] = None
data_gas_used: Optional[int] = None

@staticmethod
def from_parent_header(parent: "FixtureHeader") -> "Environment":
Expand All @@ -569,6 +571,7 @@ def from_parent_header(parent: "FixtureHeader") -> "Environment":
parent_difficulty=parent.difficulty,
parent_timestamp=parent.timestamp,
parent_base_fee=parent.base_fee,
parent_data_gas_used=parent.data_gas_used,
parent_excess_data_gas=parent.excess_data_gas,
parent_gas_used=parent.gas_used,
parent_gas_limit=parent.gas_limit,
Expand Down Expand Up @@ -599,6 +602,7 @@ def apply_new_parent(self, new_parent: "FixtureHeader") -> "Environment":
env.parent_difficulty = new_parent.difficulty
env.parent_timestamp = new_parent.timestamp
env.parent_base_fee = new_parent.base_fee
env.parent_data_gas_used = new_parent.data_gas_used
env.parent_excess_data_gas = new_parent.excess_data_gas
env.parent_gas_used = new_parent.gas_used
env.parent_gas_limit = new_parent.gas_limit
Expand Down Expand Up @@ -641,9 +645,17 @@ def set_fork_requirements(self, fork: Fork) -> "Environment":
if (
fork.header_excess_data_gas_required(self.number, self.timestamp)
and res.excess_data_gas is None
and res.parent_excess_data_gas is None
):
res.excess_data_gas = 0

if (
fork.header_data_gas_used_required(self.number, self.timestamp)
and res.data_gas_used is None
and res.parent_data_gas_used is None
):
res.data_gas_used = 0

return res


Expand Down Expand Up @@ -806,6 +818,7 @@ class Header:
nonce: Optional[str] = None
base_fee: Optional[int | Removable] = None
withdrawals_root: Optional[str | Removable] = None
data_gas_used: Optional[int | Removable] = None
excess_data_gas: Optional[int | Removable] = None
hash: Optional[str] = None

Expand Down Expand Up @@ -838,6 +851,7 @@ class FixtureHeader:
nonce: str
base_fee: Optional[int] = None
withdrawals_root: Optional[str] = None
data_gas_used: Optional[int] = None
excess_data_gas: Optional[int] = None
hash: Optional[str] = None

Expand Down Expand Up @@ -867,6 +881,7 @@ def from_dict(source: Dict[str, Any]) -> "FixtureHeader":
nonce=source["nonce"],
base_fee=int_or_none(source.get("baseFeePerGas")),
withdrawals_root=str_or_none(source.get("withdrawalsRoot")),
data_gas_used=int_or_none(source.get("dataGasUsed")),
excess_data_gas=int_or_none(source.get("excessDataGas")),
hash=source.get("hash"),
)
Expand Down Expand Up @@ -896,6 +911,8 @@ def to_geth_dict(self) -> Mapping[str, Any]:
header["baseFeePerGas"] = hex(self.base_fee)
if self.withdrawals_root is not None:
header["withdrawalsRoot"] = self.withdrawals_root
if self.data_gas_used is not None:
header["dataGasUsed"] = hex(self.data_gas_used)
if self.excess_data_gas is not None:
header["excessDataGas"] = hex(self.excess_data_gas)
return header
Expand Down Expand Up @@ -975,7 +992,8 @@ def set_environment(self, env: Environment) -> Environment:
new_env.withdrawals = self.withdrawals
if not isinstance(self.excess_data_gas, Removable):
new_env.excess_data_gas = self.excess_data_gas

if not isinstance(self.data_gas_used, Removable):
new_env.data_gas_used = self.data_gas_used
"""
These values are required, but they depend on the previous environment,
so they can be calculated here.
Expand Down Expand Up @@ -1156,8 +1174,10 @@ def default(self, obj):
"withdrawals": to_json_or_none(obj.withdrawals),
"parentUncleHash": obj.parent_ommers_hash,
"currentBaseFee": str_or_none(obj.base_fee),
"parentDataGasUsed": str_or_none(obj.parent_data_gas_used),
"parentExcessDataGas": str_or_none(obj.parent_excess_data_gas),
"currentExcessDataGas": str_or_none(obj.excess_data_gas),
"currentDataGasUsed": str_or_none(obj.data_gas_used),
}

return {k: v for (k, v) in env.items() if v is not None}
Expand Down Expand Up @@ -1185,6 +1205,8 @@ def default(self, obj):
header["hash"] = obj.hash
if obj.withdrawals_root is not None:
header["withdrawalsRoot"] = obj.withdrawals_root
if obj.data_gas_used is not None:
header["dataGasUsed"] = hex(obj.data_gas_used)
if obj.excess_data_gas is not None:
header["excessDataGas"] = hex(obj.excess_data_gas)
return even_padding(
Expand Down
1 change: 1 addition & 0 deletions src/ethereum_test_tools/spec/blockchain_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def make_genesis(
mix_digest="0x0000000000000000000000000000000000000000000000000000000000000000",
nonce="0x0000000000000000",
base_fee=env.base_fee,
data_gas_used=env.data_gas_used,
excess_data_gas=env.excess_data_gas,
withdrawals_root=t8n.calc_withdrawals_root(env.withdrawals, fork)
if env.withdrawals is not None
Expand Down
1 change: 1 addition & 0 deletions src/ethereum_test_tools/spec/state_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ def make_genesis(
mix_digest="0x0000000000000000000000000000000000000000000000000000000000000000",
nonce="0x0000000000000000",
base_fee=env.base_fee,
data_gas_used=env.data_gas_used,
excess_data_gas=env.excess_data_gas,
withdrawals_root=t8n.calc_withdrawals_root(env.withdrawals, fork)
if env.withdrawals is not None
Expand Down
13 changes: 9 additions & 4 deletions tests/eips/eip4844/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,17 @@ Predominantly verifies that `excess_data_gas` & `data_gasprice` are calculated c
Tests that the `excess_data_gas` is calculated correctly within a single block for various contexts, where the `parent.excess_data_gas` and the proposed block `excess_data_gas` have a variety of values. The excess data gas is calculated using the following formula:

```python
def calc_excess_data_gas(parent: Header, new_blobs: int) -> int:
consumed_data_gas = new_blobs * DATA_GAS_PER_BLOB
if parent.excess_data_gas + consumed_data_gas < TARGET_DATA_GAS_PER_BLOCK:
def calc_excess_data_gas(parent_excess_data_gas: int, parent_blobs: int) -> int:
"""
Calculate the excess data gas for a block given the parent excess data gas
and the number of blobs in the block.
"""
parent_consumed_data_gas = parent_blobs * DATA_GAS_PER_BLOB
if parent_excess_data_gas + parent_consumed_data_gas < TARGET_DATA_GAS_PER_BLOCK:
return 0
else:
return parent.excess_data_gas + consumed_data_gas - TARGET_DATA_GAS_PER_BLOCK
return parent_excess_data_gas + parent_consumed_data_gas - TARGET_DATA_GAS_PER_BLOCK

```

For blocks to be valid in these contexts they must meet the following conditions of the EIP:
Expand Down
Loading

0 comments on commit 5ac602e

Please sign in to comment.