diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 212c0120f2..31c2d60ac1 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -86,7 +86,7 @@ jobs: - name: Install Geth uses: gacts/install-geth-tools@v1 with: - version: 1.13.11 + version: 1.14.5 - name: Install Dependencies run: | diff --git a/setup.py b/setup.py index 25811454c7..b4f7c6f9b8 100644 --- a/setup.py +++ b/setup.py @@ -126,7 +126,7 @@ "eth-typing>=3.5.2,<4", "eth-utils>=2.3.1,<3", "hexbytes", # Peer - "py-geth>=4.4.0,<5", + "py-geth>=5.0.0-beta.2,<6", "trie>=3.0.0,<4", # Peer: stricter pin needed for uv support. "web3[tester]>=6.17.2,<7", # ** Dependencies maintained by ApeWorX ** diff --git a/src/ape_node/provider.py b/src/ape_node/provider.py index 533a2c0a33..5398942697 100644 --- a/src/ape_node/provider.py +++ b/src/ape_node/provider.py @@ -2,16 +2,16 @@ import shutil from pathlib import Path from subprocess import DEVNULL, PIPE, Popen -from typing import Optional, Union +from typing import Any, Optional, Union from eth_pydantic_types import HexBytes from eth_typing import HexStr from eth_utils import add_0x_prefix, to_hex, to_wei from evmchains import get_random_rpc -from geth.accounts import ensure_account_exists # type: ignore -from geth.chain import initialize_chain # type: ignore -from geth.process import BaseGethProcess # type: ignore -from geth.wrapper import construct_test_chain_kwargs # type: ignore +from geth.chain import initialize_chain +from geth.process import BaseGethProcess +from geth.types import GenesisDataTypedDict +from geth.wrapper import construct_test_chain_kwargs from pydantic import field_validator from pydantic_settings import SettingsConfigDict from requests.exceptions import ConnectionError @@ -26,6 +26,7 @@ DEFAULT_TEST_CHAIN_ID, DEFAULT_TEST_HD_PATH, DEFAULT_TEST_MNEMONIC, + ZERO_ADDRESS, JoinableQueue, generate_dev_accounts, log_instead_of_fail, @@ -40,6 +41,49 @@ ) from ape_ethereum.trace import TraceApproach +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", + "gasLimit": "0x0", + "extraData": "0x", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x0", + "timestamp": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "baseFeePerGas": "0x0", + } + class GethDevProcess(BaseGethProcess): """ @@ -64,10 +108,10 @@ def __init__( if not shutil.which(executable): raise NodeSoftwareNotInstalledError() - self.data_dir = data_dir + self._data_dir = data_dir self._hostname = hostname self._port = port - self.data_dir.mkdir(exist_ok=True, parents=True) + self._data_dir.mkdir(exist_ok=True, parents=True) self.is_running = False self._auto_disconnect = auto_disconnect @@ -75,8 +119,8 @@ def __init__( data_dir=self.data_dir, geth_executable=executable, rpc_addr=hostname, - rpc_port=port, - network_id=chain_id, + rpc_port=f"{port}", + network_id=f"{chain_id}", ws_enabled=False, ws_addr=None, ws_origins=None, @@ -87,8 +131,7 @@ def __init__( # Ensure a clean data-dir. self._clean() - sealer = ensure_account_exists(**geth_kwargs).decode().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 ) @@ -96,34 +139,9 @@ def __init__( addresses.extend(extra_funded_accounts or []) bal_dict = {"balance": str(initial_balance)} alloc = {a: bal_dict for a in addresses} - genesis_data: dict = { - "overwrite": True, - "coinbase": "0x0000000000000000000000000000000000000000", - "difficulty": "0x0", - "extraData": f"0x{'0' * 64}{sealer}{'0' * 130}", - "config": { - "chainId": chain_id, - "gasLimit": 0, - "homesteadBlock": 0, - "difficulty": "0x0", - "eip150Block": 0, - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "berlinBlock": 0, - "londonBlock": 0, - "parisBlock": 0, - "shanghaiTime": 0, - "clique": {"period": 0, "epoch": 30000}, - }, - "alloc": alloc, - } - - initialize_chain(genesis_data, **geth_kwargs) - self.proc: Optional[Popen] = None + 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) @classmethod @@ -152,6 +170,10 @@ def from_uri(cls, uri: str, data_folder: Path, **kwargs): hd_path=kwargs.get("hd_path", DEFAULT_TEST_HD_PATH), ) + @property + def data_dir(self) -> str: + return f"{self._data_dir}" + def connect(self, timeout: int = 60): home = str(Path.home()) ipc_path = self.ipc_path.replace(home, "$HOME") @@ -184,8 +206,8 @@ def disconnect(self): self._clean() def _clean(self): - if self.data_dir.is_dir(): - shutil.rmtree(self.data_dir) + if self._data_dir.is_dir(): + shutil.rmtree(self._data_dir) def wait(self, *args, **kwargs): if self.proc is None: diff --git a/tests/functional/geth/test_provider.py b/tests/functional/geth/test_provider.py index bc06e9850f..5015d2fc58 100644 --- a/tests/functional/geth/test_provider.py +++ b/tests/functional/geth/test_provider.py @@ -223,7 +223,7 @@ def test_get_block(geth_provider, block_id): # Each parameter is the same as requesting the first block. assert block.number == 0 - assert block.base_fee == 1000000000 + assert block.base_fee == 0 assert block.gas_used == 0