Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tests/4844: excessDataGas and dataGasUsed spec update #139

Merged
merged 21 commits into from
Jun 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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