Repository: ethereum/py-geth

Issue:
Unable to set chainId in geth --dev genesis config
### What happened?

to get the new geth and py-geth to work in Ape, I had to make a silly edition to the code:

```python
class GenesisDataConfig(BaseModel):
    chainId: int = 0
    ...
```

just adds chain ID.
Otherwise, my transactions were all failing with `Invalid sender` for my accounts.
With this change, I can set the chain Id and make transactions in my dev environment whilst overriding the genesis...

Perhaps there is an alternative in the meantime I am unaware of?

### Code that produced the error

```python
Alloc = dict[str, dict[str, Any]]


def create_genesis_data(alloc: Alloc, chain_id: int) -> GenesisDataTypedDict:
    """
    A wrapper around genesis data for py-geth that
    fills in more defaults.
    """
    return {
        "alloc": alloc,
        "config": {
            "arrowGlacierBlock": 0,
            "berlinBlock": 0,
            "byzantiumBlock": 0,
            "cancunTime": 0,
            "chainId": chain_id,
            "constantinopleBlock": 0,
            "daoForkBlock": 0,
            "daoForkSupport": True,
            "eip150Block": 0,
            "eip155Block": 0,
            "eip158Block": 0,
            "ethash": {},
            "grayGlacierBlock": 0,
            "homesteadBlock": 0,
            "istanbulBlock": 0,
            "londonBlock": 0,
            "petersburgBlock": 0,
            "shanghaiTime": 0,
            "terminalTotalDifficulty": 0,
            "terminalTotalDifficultyPassed": True,
        },
        "coinbase": ZERO_ADDRESS,
        "difficulty": "0x0",
        "extraData": "0x",
        "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
        "nonce": "0x0",
        "timestamp": "0x0",
        "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    }


class GethDevProcess(BaseGethProcess):
    """
    A developer-configured geth that only exists until disconnected.
    """

    def __init__(
        self,
        data_dir: Path,
        hostname: str = DEFAULT_HOSTNAME,
        port: int = DEFAULT_PORT,
        mnemonic: str = DEFAULT_TEST_MNEMONIC,
        number_of_accounts: int = DEFAULT_NUMBER_OF_TEST_ACCOUNTS,
        chain_id: int = DEFAULT_TEST_CHAIN_ID,
        initial_balance: Union[str, int] = to_wei(10000, "ether"),
        executable: Optional[str] = None,
        auto_disconnect: bool = True,
        extra_funded_accounts: Optional[list[str]] = None,
        hd_path: Optional[str] = DEFAULT_TEST_HD_PATH,
    ):
        executable = executable or "geth"
        if not shutil.which(executable):
            raise NodeSoftwareNotInstalledError()

        self._data_dir = data_dir
        self._hostname = hostname
        self._port = port
        self._data_dir.mkdir(exist_ok=True, parents=True)
        self.is_running = False
        self._auto_disconnect = auto_disconnect

        geth_kwargs = construct_test_chain_kwargs(
            data_dir=self.data_dir,
            geth_executable=executable,
            rpc_addr=hostname,
            rpc_port=f"{port}",
            network_id=f"{chain_id}",
            ws_enabled=False,
            ws_addr=None,
            ws_origins=None,
            ws_port=None,
            ws_api=None,
        )

        # Ensure a clean data-dir.
        self._clean()

        # sealer = ensure_account_exists(**geth_kwargs).replace("0x", "")
        # geth_kwargs["miner_etherbase"] = sealer
        geth_kwargs["dev_mode"] = True
        accounts = generate_dev_accounts(
            mnemonic, number_of_accounts=number_of_accounts, hd_path=hd_path or DEFAULT_TEST_HD_PATH
        )
        addresses = [a.address for a in accounts]
        addresses.extend(extra_funded_accounts or [])
        bal_dict = {"balance": str(initial_balance)}
        alloc = {a: bal_dict for a in addresses}
        genesis = create_genesis_data(alloc, chain_id)
        self._data_dir.mkdir(parents=True, exist_ok=True)
        initialize_chain(genesis, self.data_dir)
        super().__init__(geth_kwargs)
```


### Full error output

```shell
geth.exceptions.PyGethValueError: genesis_data config field validation failed: 1 validation error for GenesisDataConfig
E               chainId
E                 Extra inputs are not permitted [type=extra_forbidden, input_value=1337, input_type=int]
E                   For further information visit https://errors.pydantic.dev/2.7/v/extra_forbidden


but if i exclude chainId i got this:

(-32000) invalid sender
```


### Fill this section in if you know how this could or should be fixed

Allow chainId to be set on the model.
Doing this fixed the issue for me!

### py-geth Version

5.0.0b1

### Python Version

Python 3.12.2

### Operating System

macOS intel

### Output from `pip freeze`

```shell
i will paste if needed but it is not a pretty freeze.
```


Discussion:
kclowes: Thanks for the PR! I added a few more that I noticed were missing. 
kclowes: @antazoey I also changed `mixhash` -> `mixHash` to match geth, let me know if that throws you off and I'll change it back!
antazoey: > @antazoey I also changed `mixhash` -> `mixHash` to match geth, let me know if that throws you off and I'll change it back!

I had it that way before. So that works!

Patch:
diff --git a/geth/genesis.json b/geth/genesis.json
index aa20d22..e031182 100644
--- a/geth/genesis.json
+++ b/geth/genesis.json
@@ -24,6 +24,6 @@
     "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000",
     "gasLimit": "0x47e7c4",
     "difficulty": "0x0",
-    "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
+    "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
     "alloc": {}
 }
diff --git a/geth/types.py b/geth/types.py
index 85b8076..01b1e15 100644
--- a/geth/types.py
+++ b/geth/types.py
@@ -48,12 +48,17 @@ class GethKwargsTypedDict(TypedDict, total=False):
 
 class GenesisDataTypedDict(TypedDict, total=False):
     alloc: dict[str, dict[str, Any]]
+    baseFeePerGas: str
+    blobGasUsed: str
     coinbase: str
     config: dict[str, Any]
     difficulty: str
+    excessBlobGas: str
     extraData: str
     gasLimit: str
-    mixhash: str
+    gasUsed: str
+    mixHash: str
     nonce: str
+    number: str
     parentHash: str
     timestamp: str
diff --git a/geth/utils/validation.py b/geth/utils/validation.py
index 19e9d4b..c9e18e8 100644
--- a/geth/utils/validation.py
+++ b/geth/utils/validation.py
@@ -70,6 +70,7 @@ def validate_geth_kwargs(geth_kwargs: GethKwargsTypedDict) -> None:
 
 
 class GenesisDataConfig(BaseModel):
+    chainId: int = 0
     ethash: dict[str, Any] = {}  # so that geth treats config as PoW -> PoS transition
     homesteadBlock: int = 0
     daoForkBlock: int = 0
@@ -97,15 +98,20 @@ class GenesisDataConfig(BaseModel):
 
 class GenesisData(BaseModel):
     alloc: dict[str, dict[str, Any]] = {}
+    baseFeePerGas: str = "0x0"
+    blobGasUsed: str = "0x0"
     coinbase: str = "0x3333333333333333333333333333333333333333"
     config: dict[str, Any] = GenesisDataConfig().model_dump()
     difficulty: str = "0x0"
+    excessBlobGas: str = "0x0"
     extraData: str = (
         "0x0000000000000000000000000000000000000000000000000000000000000000"
     )
     gasLimit: str = "0x47e7c4"
-    mixhash: str = "0x0000000000000000000000000000000000000000000000000000000000000000"
+    gasUsed: str = "0x0"
+    mixHash: str = "0x0000000000000000000000000000000000000000000000000000000000000000"
     nonce: str = "0x0"
+    number: str = "0x0"
     parentHash: str = (
         "0x0000000000000000000000000000000000000000000000000000000000000000"
     )
diff --git a/newsfragments/221.bugfix.rst b/newsfragments/221.bugfix.rst
new file mode 100644
index 0000000..430b16e
--- /dev/null
+++ b/newsfragments/221.bugfix.rst
@@ -0,0 +1,1 @@
+Add missing fields for genesis data. Change mixhash -> mixHash to more closely match Geth


Test patch:
diff --git a/tests/core/utility/test_validation.py b/tests/core/utility/test_validation.py
index 55fb837..3d4a262 100644
--- a/tests/core/utility/test_validation.py
+++ b/tests/core/utility/test_validation.py
@@ -104,8 +104,11 @@ def test_validate_genesis_data_bad(genesis_data):
             },
             {
                 "alloc": {},
+                "baseFeePerGas": "0x0",
+                "blobGasUsed": "0x0",
                 "coinbase": "0x3333333333333333333333333333333333333333",
                 "config": {
+                    "chainId": 0,
                     "ethash": {},
                     "homesteadBlock": 0,
                     "daoForkBlock": 0,
@@ -127,10 +130,13 @@ def test_validate_genesis_data_bad(genesis_data):
                     "cancunTime": 0,
                 },
                 "difficulty": "0x00012131",
+                "excessBlobGas": "0x0",
                 "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000",  # noqa: E501
                 "gasLimit": "0x47e7c4",
-                "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",  # noqa: E501
+                "gasUsed": "0x0",
+                "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",  # noqa: E501
                 "nonce": "abc",
+                "number": "0x0",
                 "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",  # noqa: E501
                 "timestamp": "1234",
             },
@@ -150,8 +156,11 @@ def test_validate_genesis_data_bad(genesis_data):
             },
             {
                 "alloc": {},
+                "baseFeePerGas": "0x0",
+                "blobGasUsed": "0x0",
                 "coinbase": "0x3333333333333333333333333333333333333333",
                 "config": {
+                    "chainId": 0,
                     "ethash": {},
                     "homesteadBlock": 5,
                     "daoForkBlock": 1,
@@ -173,10 +182,13 @@ def test_validate_genesis_data_bad(genesis_data):
                     "cancunTime": 0,
                 },
                 "difficulty": "0x00012131",
+                "excessBlobGas": "0x0",
                 "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000",  # noqa: E501
                 "gasLimit": "0x47e7c4",
-                "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",  # noqa: E501
+                "gasUsed": "0x0",
+                "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",  # noqa: E501
                 "nonce": "abc",
+                "number": "0x0",
                 "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",  # noqa: E501
                 "timestamp": "0x0",
             },