Repository: ethereum/web3.py
Pull request #3659: Prague updates
Author: login: fselmo
Labels: name: priority: p0 urgent
Created: 2025-04-10T23:02:14Z | Merged: 2025-04-28T20:56:57Z

### What was wrong?

We need to add some additional support for Prague-related fields.

### How was it fixed?

- Add formatters for authorization list fields and block requests field in block headers
- Add integration test for 7702 so both geth and py-evm interactions are tested with expected results

--- 
Significant change to integration tests:

Change integration tests so that each test has its own context. We are having way too many issues with muddied contexts and tests needing to wait on the right moment to test transactions between a mining state. This isolates each integration test into its own state which makes issues a lot easier to track and should give less CI headaches.

---

### Todo:

- [x] Clean up commit history
- [x] Add or update documentation related to these changes --> This probably needs to be better... future PR + blog post?
- [x] Add at least one good 7702 tx test to the integration tests so we can test across both geth and eth-tester <-> py-evm
- [x] Will need ethereum/eth-tester#317 and a release which is waiting on a *py-evm* Prague release. Update eth-tester lower pin when release is ready.
- [x] Add entry to the [release notes](https://github.com/ethereum/web3.py/blob/main/newsfragments/README.md)

#### Cute Animal Picture

<img width="714" alt="Screenshot 2025-04-23 at 13 19 00" src="https://github.com/user-attachments/assets/1ec4642e-289f-4a19-8e51-4905f76014d3" />


Diff:
diff --git a/docs/contributing.rst b/docs/contributing.rst
index f44fbcd3a7..a9ed3e03ba 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -160,6 +160,7 @@ Within the ``pytest`` scope, :file:`conftest.py` files are used for common code
 shared between modules that exist within the same directory as that particular
 :file:`conftest.py` file.
 
+
 Unit Testing and eth-tester Tests
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -200,6 +201,16 @@ tests are written across different files within ``/web3/_utils/module_testing``.
   client-and-provider-specific test configurations exist. This is mostly used to
   override tests specific to the provider type for the respective client.
 
+The integration tests are each run in insolation to prevent muddied contexts. Because
+they are run in isolation, they can be parallelized with ``pytest-xdist`` in order to
+speed up the test suite. To run the tests in parallel, you can use the ``-n`` flag
+with ``pytest``. For example, to run the tests in parallel with 4 workers, you can
+use the following command:
+
+.. code:: sh
+
+    $ pytest tests/integration/go_ethereum/path/to/module/or/test -n 4
+
 
 Working With Test Contracts
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/newsfragments/3659.feature.rst b/newsfragments/3659.feature.rst
new file mode 100644
index 0000000000..b34dfdb5c6
--- /dev/null
+++ b/newsfragments/3659.feature.rst
@@ -0,0 +1 @@
+Support for Prague network upgrade, mainly ``requests_hash`` and ``authorization_list`` formatters. Add support for serializing ``SignedSetCodeTransaction`` (`eth-account` pydantic model) directly added to transaction dicts.
diff --git a/newsfragments/3659.internal.rst b/newsfragments/3659.internal.rst
new file mode 100644
index 0000000000..49146e985b
--- /dev/null
+++ b/newsfragments/3659.internal.rst
@@ -0,0 +1 @@
+Run each integration test in isolation and parallelize, instead of running them all within a single `geth` (for example) process. This prevents muddied test contexts.
diff --git a/setup.py b/setup.py
index 74027d53fe..0757810e53 100644
--- a/setup.py
+++ b/setup.py
@@ -8,7 +8,7 @@
     "tester": [
         # Note: ethereum-maintained libraries in this list should be added to the
         # `install_pre_releases.py` script.
-        "eth-tester[py-evm]>=0.12.0b1,<0.13.0b1",
+        "eth-tester[py-evm]>=0.13.0b1,<0.14.0b1",
         "py-geth>=5.1.0",
     ],
     "dev": [
@@ -67,7 +67,7 @@
         # Note: ethereum-maintained libraries in this list should be added to the
         # `install_pre_releases.py` script.
         "eth-abi>=5.0.1",
-        "eth-account>=0.13.1",
+        "eth-account>=0.13.6",
         "eth-hash[pycryptodome]>=0.5.1",
         "eth-typing>=5.0.0",
         "eth-utils>=5.0.0",
diff --git a/tests/conftest.py b/tests/conftest.py
index 3e13bd6c30..66ea6dd086 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -19,21 +19,12 @@
     RequestMocker,
 )
 
-from .utils import (
-    get_open_port,
-)
-
 
 @pytest.fixture(scope="module", params=[lambda x: to_bytes(hexstr=x), identity])
 def address_conversion_func(request):
     return request.param
 
 
-@pytest.fixture()
-def open_port():
-    return get_open_port()
-
-
 # --- session-scoped constants --- #
 
 
diff --git a/tests/core/eth-module/test_block_api.py b/tests/core/eth-module/test_block_api.py
index e295953181..5479f11591 100644
--- a/tests/core/eth-module/test_block_api.py
+++ b/tests/core/eth-module/test_block_api.py
@@ -46,6 +46,7 @@ def test_get_block_formatters_with_null_values(w3, request_mocker):
         "blobGasUsed": None,
         "excessBlobGas": None,
         "parentBeaconBlockRoot": None,
+        "requestsHash": None,
     }
     with request_mocker(w3, mock_results={"eth_getBlockByNumber": null_values_block}):
         received_block = w3.eth.get_block("pending")
@@ -109,6 +110,9 @@ def test_get_block_formatters_with_pre_formatted_values(w3, request_mocker):
         "parentBeaconBlockRoot": (
             "0x6470e77f1b8a55a49a57b3f74c2a10a76185636d65122053752ea5e4bb4dac59"
         ),
+        "requestsHash": (
+            "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+        ),
     }
 
     with request_mocker(
@@ -170,4 +174,5 @@ def test_get_block_formatters_with_pre_formatted_values(w3, request_mocker):
         "parentBeaconBlockRoot": HexBytes(
             unformatted_values_block["parentBeaconBlockRoot"]
         ),
+        "requestsHash": HexBytes(unformatted_values_block["requestsHash"]),
     }
diff --git a/tests/core/eth-module/test_transactions.py b/tests/core/eth-module/test_transactions.py
index 040a309599..a71733d4b1 100644
--- a/tests/core/eth-module/test_transactions.py
+++ b/tests/core/eth-module/test_transactions.py
@@ -2,6 +2,9 @@
 import collections
 import itertools
 
+from eth_account import (
+    Account,
+)
 from eth_utils import (
     to_checksum_address,
     to_int,
@@ -9,7 +12,15 @@
 from hexbytes import (
     HexBytes,
 )
+import pytest_asyncio
 
+from tests.core.contracts.utils import (
+    async_deploy,
+    deploy,
+)
+from web3._utils.contract_sources.contract_data.math_contract import (
+    MATH_CONTRACT_DATA,
+)
 from web3._utils.ens import (
     ens_addresses,
 )
@@ -29,6 +40,12 @@
 RECEIPT_TIMEOUT = 0.2
 
 
+@pytest.fixture
+def math_contract(w3):
+    factory = w3.eth.contract(**MATH_CONTRACT_DATA)
+    return deploy(w3, factory)
+
+
 def _tx_indexing_response_iterator():
     while True:
         yield {"error": {"message": "transaction indexing in progress"}}
@@ -371,9 +388,86 @@ def test_eth_send_raw_blob_transaction(w3):
     )
 
 
+def test_send_set_code_transaction(w3, math_contract):
+    pkey = w3.provider.ethereum_tester.backend.account_keys[0]
+    acct = Account.from_key(pkey)
+
+    nonce = w3.eth.get_transaction_count(acct.address)
+    chain_id = w3.eth.chain_id
+
+    auth = {
+        "chainId": chain_id,
+        "address": math_contract.address,
+        "nonce": nonce + 1,
+    }
+    signed_auth = acct.sign_authorization(auth)
+
+    # get current math counter and increase it only in the delegation by n
+    math_counter = math_contract.functions.counter().call()
+    built_tx = math_contract.functions.incrementCounter(
+        math_counter + 1337
+    ).build_transaction({})
+    txn = {
+        "chainId": chain_id,
+        "to": acct.address,
+        "value": 0,
+        "gas": 200_000,
+        "nonce": nonce,
+        "maxPriorityFeePerGas": 10**9,
+        "maxFeePerGas": 10**9,
+        "data": built_tx["data"],
+        "authorizationList": [signed_auth],
+    }
+
+    tx_hash = w3.eth.send_transaction(txn)
+    get_tx = w3.eth.get_transaction(tx_hash)
+    w3.eth.wait_for_transaction_receipt(tx_hash, timeout=10)
+
+    code = w3.eth.get_code(acct.address)
+
+    assert code.to_0x_hex().lower() == f"0xef0100{math_contract.address[2:].lower()}"
+    delegated = w3.eth.contract(address=acct.address, abi=math_contract.abi)
+    # assert the math counter is increased by 1337 only in delegated acct
+    assert math_contract.functions.counter().call() == math_counter
+    delegated_call = delegated.functions.counter().call()
+    assert delegated_call == math_counter + 1337
+
+    assert len(get_tx["authorizationList"]) == 1
+    get_auth = get_tx["authorizationList"][0]
+    assert get_auth["chainId"] == chain_id
+    assert get_auth["address"].lower() == math_contract.address.lower()
+    assert get_auth["nonce"] == nonce + 1
+    assert isinstance(get_auth["yParity"], int)
+    assert isinstance(get_auth["r"], HexBytes)
+    assert isinstance(get_auth["s"], HexBytes)
+
+    # reset code
+    reset_auth = {
+        "chainId": chain_id,
+        "address": "0x" + ("00" * 20),
+        "nonce": nonce + 3,
+    }
+    signed_reset_auth = acct.sign_authorization(reset_auth)
+    new_txn = dict(txn)
+    new_txn["authorizationList"] = [signed_reset_auth]
+    new_txn["nonce"] = nonce + 2
+
+    reset_tx_hash = w3.eth.send_transaction(new_txn)
+    w3.eth.wait_for_transaction_receipt(reset_tx_hash, timeout=10)
+
+    reset_code = w3.eth.get_code(acct.address)
+    assert reset_code == HexBytes("0x")
+
+
 # --- async --- #
 
 
+@pytest_asyncio.fixture
+async def async_math_contract(async_w3):
+    factory = async_w3.eth.contract(**MATH_CONTRACT_DATA)
+    return await async_deploy(async_w3, factory)
+
+
 @pytest.mark.asyncio
 async def test_async_wait_for_transaction_receipt_transaction_indexing_in_progress(
     async_w3, request_mocker
@@ -420,3 +514,77 @@ async def test_async_send_raw_blob_transaction(async_w3):
     assert transaction["blobVersionedHashes"][0] == HexBytes(
         "0x0127c38bcad458d932e828b580b9ad97310be01407dfa0ed88118735980a3e9a"
     )
+
+
+@pytest.mark.asyncio
+async def test_async_send_set_code_transaction(async_w3, async_math_contract):
+    pkey = async_w3.provider.ethereum_tester.backend.account_keys[0]
+    acct = Account.from_key(pkey)
+
+    nonce = await async_w3.eth.get_transaction_count(acct.address)
+    chain_id = await async_w3.eth.chain_id
+
+    auth = {
+        "chainId": chain_id,
+        "address": async_math_contract.address,
+        "nonce": nonce + 1,
+    }
+    signed_auth = acct.sign_authorization(auth)
+
+    # get current math counter and increase it only in the delegation by n
+    math_counter = await async_math_contract.functions.counter().call()
+    built_tx = await async_math_contract.functions.incrementCounter(
+        math_counter + 1337
+    ).build_transaction({})
+    txn = {
+        "chainId": chain_id,
+        "to": acct.address,
+        "value": 0,
+        "gas": 200_000,
+        "nonce": nonce,
+        "maxPriorityFeePerGas": 10**9,
+        "maxFeePerGas": 10**9,
+        "data": built_tx["data"],
+        "authorizationList": [signed_auth],
+    }
+
+    tx_hash = await async_w3.eth.send_transaction(txn)
+    get_tx = await async_w3.eth.get_transaction(tx_hash)
+    await async_w3.eth.wait_for_transaction_receipt(tx_hash, timeout=10)
+
+    code = await async_w3.eth.get_code(acct.address)
+
+    assert (
+        code.to_0x_hex().lower() == f"0xef0100{async_math_contract.address[2:].lower()}"
+    )
+    delegated = async_w3.eth.contract(address=acct.address, abi=async_math_contract.abi)
+    # assert the math counter is increased by 1337 only in delegated acct
+    assert await async_math_contract.functions.counter().call() == math_counter
+    delegated_call = await delegated.functions.counter().call()
+    assert delegated_call == math_counter + 1337
+
+    assert len(get_tx["authorizationList"]) == 1
+    get_auth = get_tx["authorizationList"][0]
+    assert get_auth["chainId"] == chain_id
+    assert get_auth["address"].lower() == async_math_contract.address.lower()
+    assert get_auth["nonce"] == nonce + 1
+    assert isinstance(get_auth["yParity"], int)
+    assert isinstance(get_auth["r"], HexBytes)
+    assert isinstance(get_auth["s"], HexBytes)
+
+    # reset code
+    reset_auth = {
+        "chainId": chain_id,
+        "address": "0x" + ("00" * 20),
+        "nonce": nonce + 3,
+    }
+    signed_reset_auth = acct.sign_authorization(reset_auth)
+    new_txn = dict(txn)
+    new_txn["authorizationList"] = [signed_reset_auth]
+    new_txn["nonce"] = nonce + 2
+
+    reset_tx_hash = await async_w3.eth.send_transaction(new_txn)
+    await async_w3.eth.wait_for_transaction_receipt(reset_tx_hash, timeout=10)
+
+    reset_code = await async_w3.eth.get_code(acct.address)
+    assert reset_code == HexBytes("0x")
diff --git a/tests/core/providers/test_legacy_websocket_provider.py b/tests/core/providers/test_legacy_websocket_provider.py
index ae4e84b612..46d1884a0b 100644
--- a/tests/core/providers/test_legacy_websocket_provider.py
+++ b/tests/core/providers/test_legacy_websocket_provider.py
@@ -1,19 +1,5 @@
 import pytest
-import asyncio
-from asyncio.exceptions import (
-    TimeoutError,
-)
-from threading import (
-    Thread,
-)
-
-from websockets.legacy.server import (
-    serve,
-)
 
-from tests.utils import (
-    wait_for_ws,
-)
 from web3 import (
     Web3,
 )
@@ -26,39 +12,6 @@
 )
 
 
-@pytest.fixture
-def start_websocket_server(open_port):
-    event_loop = asyncio.new_event_loop()
-
-    def run_server():
-        async def empty_server(websocket, path):
-            data = await websocket.recv()
-            await asyncio.sleep(0.02)
-            await websocket.send(data)
-
-        asyncio.set_event_loop(event_loop)
-        server = serve(empty_server, "127.0.0.1", open_port)
-        event_loop.run_until_complete(server)
-        event_loop.run_forever()
-
-    thd = Thread(target=run_server)
-    thd.start()
-    try:
-        yield
-    finally:
-        event_loop.call_soon_threadsafe(event_loop.stop)
-
-
-@pytest.fixture
-def w3(open_port, start_websocket_server):
-    # need new event loop as the one used by server is already running
-    event_loop = asyncio.new_event_loop()
-    endpoint_uri = f"ws://127.0.0.1:{open_port}"
-    event_loop.run_until_complete(wait_for_ws(endpoint_uri))
-    provider = LegacyWebSocketProvider(endpoint_uri, websocket_timeout=0.01)
-    return Web3(provider)
-
-
 def test_no_args():
     provider = LegacyWebSocketProvider()
     w3 = Web3(provider)
@@ -69,11 +22,6 @@ def test_no_args():
         w3.is_connected(show_traceback=True)
 
 
-def test_websocket_provider_timeout(w3):
-    with pytest.raises(TimeoutError):
-        w3.eth.accounts
-
-
 def test_restricted_websocket_kwargs():
     invalid_kwargs = {"uri": "ws://127.0.0.1:8546"}
     re_exc_message = f".*found: {set(invalid_kwargs)!r}*"
diff --git a/tests/integration/common.py b/tests/integration/common.py
index 6d1489d1c0..968f6f9fa7 100644
--- a/tests/integration/common.py
+++ b/tests/integration/common.py
@@ -13,11 +13,11 @@
 
 
 class MiscWebSocketTest:
-    def test_websocket_max_size_error(self, w3, endpoint_uri):
-        w3 = Web3(
+    def test_websocket_max_size_error(self, w3):
+        w3_ = Web3(
             Web3.LegacyWebSocketProvider(
-                endpoint_uri=endpoint_uri, websocket_kwargs={"max_size": 1}
+                endpoint_uri=w3.provider.endpoint_uri, websocket_kwargs={"max_size": 1}
             )
         )
         with pytest.raises((OSError, ConnectionClosed)):
-            w3.eth.get_block(0)
+            w3_.eth.get_block(0)
diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py
index 3cef5b7afb..fe345f45b6 100644
--- a/tests/integration/conftest.py
+++ b/tests/integration/conftest.py
@@ -19,7 +19,7 @@
 )
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def math_contract_factory(w3):
     contract_factory = w3.eth.contract(
         abi=MATH_CONTRACT_ABI, bytecode=MATH_CONTRACT_BYTECODE
@@ -27,7 +27,7 @@ def math_contract_factory(w3):
     return contract_factory
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def emitter_contract_factory(w3):
     contract_factory = w3.eth.contract(
         abi=EMITTER_CONTRACT_ABI, bytecode=EMITTER_CONTRACT_BYTECODE
@@ -35,7 +35,7 @@ def emitter_contract_factory(w3):
     return contract_factory
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def revert_contract_factory(w3):
     contract_factory = w3.eth.contract(
         abi=REVERT_CONTRACT_ABI, bytecode=REVERT_CONTRACT_BYTECODE
@@ -43,7 +43,7 @@ def revert_contract_factory(w3):
     return contract_factory
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def offchain_lookup_contract_factory(w3):
     contract_factory = w3.eth.contract(
         abi=OFFCHAIN_LOOKUP_ABI, bytecode=OFFCHAIN_LOOKUP_BYTECODE
@@ -51,7 +51,7 @@ def offchain_lookup_contract_factory(w3):
     return contract_factory
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def async_offchain_lookup_contract_factory(async_w3):
     contract_factory = async_w3.eth.contract(
         abi=OFFCHAIN_LOOKUP_ABI, bytecode=OFFCHAIN_LOOKUP_BYTECODE
@@ -59,7 +59,7 @@ def async_offchain_lookup_contract_factory(async_w3):
     return contract_factory
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def event_loop():
     loop = asyncio.get_event_loop_policy().new_event_loop()
     yield loop
diff --git a/tests/integration/go_ethereum/conftest.py b/tests/integration/go_ethereum/conftest.py
index bbc96d3946..06627c64b1 100644
--- a/tests/integration/go_ethereum/conftest.py
+++ b/tests/integration/go_ethereum/conftest.py
@@ -4,12 +4,13 @@
 from pathlib import (
     Path,
 )
+import re
 import subprocess
+import time
 import zipfile
 
 from eth_utils import (
     is_dict,
-    to_text,
 )
 import pytest_asyncio
 
@@ -37,7 +38,7 @@
 GETH_FIXTURE_ZIP = "geth-1.15.5-fixture.zip"
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def geth_binary():
     from geth.install import (
         get_executable_path,
@@ -67,7 +68,7 @@ def absolute_datadir(directory_name):
     )
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def get_geth_version(geth_binary):
     from geth import (
         get_geth_version,
@@ -86,7 +87,7 @@ def get_geth_version(geth_binary):
     return geth_version
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def base_geth_command_arguments(geth_binary, datadir):
     return (
         geth_binary,
@@ -94,7 +95,7 @@ def base_geth_command_arguments(geth_binary, datadir):
         datadir,
         "--dev",
         "--dev.period",
-        "2",
+        "3",
         "--password",
         os.path.join(datadir, "keystore", "pw.txt"),
         # in order to raise on underpriced transactions, ``txpool.nolocals`` is now
@@ -103,7 +104,7 @@ def base_geth_command_arguments(geth_binary, datadir):
     )
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def geth_zipfile_version(get_geth_version):
     # TODO: Remove support for 1.13.x in next major version
     if get_geth_version.major == 1 and get_geth_version.minor in [13, 14, 15]:
@@ -111,7 +112,7 @@ def geth_zipfile_version(get_geth_version):
     raise AssertionError("Unsupported geth version")
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def datadir(tmpdir_factory, geth_zipfile_version):
     zipfile_path = absolute_datadir(geth_zipfile_version)
     base_dir = tmpdir_factory.mktemp("goethereum")
@@ -121,144 +122,161 @@ def datadir(tmpdir_factory, geth_zipfile_version):
     return tmp_datadir
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def geth_fixture_data(datadir):
     config_file_path = Path(datadir) / "config.json"
     return json.loads(config_file_path.read_text())
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def genesis_file(datadir):
     genesis_file_path = os.path.join(datadir, "genesis.json")
     return genesis_file_path
 
 
-@pytest.fixture(scope="module")
-def geth_process(geth_binary, datadir, genesis_file, geth_command_arguments):
-    init_datadir_command = (
+def wait_for_port(proc, timeout=10):
+    start = time.time()
+    wait_time = start + timeout
+
+    while time.time() < wait_time:
+        line = proc.stderr.readline()
+        if not line:
+            continue
+        elif "geth.ipc" in line:
+            # ipc path will be retrieved via ``get_ipc_path()`` fixture
+            return None
+        elif match := re.compile(r"127\.0\.0\.1:(\d+)").search(line):
+            port = int(match.group(1))
+            if port not in {0, 80}:
+                # remove false positive matches
+                return port
+
+    raise TimeoutError(f"Did not find port in logs within {timeout} seconds")
+
+
+@pytest.fixture
+def start_geth_process_and_yield_port(
+    geth_binary, datadir, genesis_file, geth_command_arguments
+):
+    init_cmd = (
         geth_binary,
         "--datadir",
         str(datadir),
         "init",
         str(genesis_file),
     )
-    subprocess.check_output(
-        init_datadir_command,
-        stdin=subprocess.PIPE,
-        stderr=subprocess.PIPE,
-    )
+    subprocess.check_output(init_cmd, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
     proc = subprocess.Popen(
         geth_command_arguments,
         stdin=subprocess.PIPE,
         stdout=subprocess.PIPE,
         stderr=subprocess.PIPE,
+        text=True,
+        bufsize=1,
     )
-    try:
-        yield proc
-    finally:
-        kill_proc_gracefully(proc)
-        output, errors = proc.communicate()
-        print(
-            "Geth Process Exited:\n"
-            f"stdout:{to_text(output)}\n\n"
-            f"stderr:{to_text(errors)}\n\n"
-        )
+
+    port = wait_for_port(proc)
+    yield port
+
+    kill_proc_gracefully(proc)
+    output, errors = proc.communicate(timeout=5)
+    print("Geth Process Exited:\n" f"stdout: {output}\n\n" f"stderr: {errors}\n\n")
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def math_contract_deploy_txn_hash(geth_fixture_data):
     return geth_fixture_data["math_deploy_txn_hash"]
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def math_contract(math_contract_factory, geth_fixture_data):
     return math_contract_factory(address=geth_fixture_data["math_address"])
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def math_contract_address(math_contract, address_conversion_func):
     return address_conversion_func(math_contract.address)
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def emitter_contract(emitter_contract_factory, geth_fixture_data):
     return emitter_contract_factory(address=geth_fixture_data["emitter_address"])
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def emitter_contract_address(emitter_contract, address_conversion_func):
     return address_conversion_func(emitter_contract.address)
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def keyfile_account_pkey(geth_fixture_data):
     return geth_fixture_data["keyfile_account_pkey"]
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def keyfile_account_address(geth_fixture_data):
     return geth_fixture_data["keyfile_account_address"]
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def keyfile_account_address_dual_type(keyfile_account_address, address_conversion_func):
     yield keyfile_account_address
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def empty_block(w3, geth_fixture_data):
     block = w3.eth.get_block(geth_fixture_data["empty_block_hash"])
     assert is_dict(block)
     return block
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def block_with_txn(w3, geth_fixture_data):
     block = w3.eth.get_block(geth_fixture_data["block_with_txn_hash"])
     assert is_dict(block)
     return block
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def mined_txn_hash(geth_fixture_data):
     return geth_fixture_data["mined_txn_hash"]
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def block_with_txn_with_log(w3, geth_fixture_data):
     block = w3.eth.get_block(geth_fixture_data["block_hash_with_log"])
     assert is_dict(block)
     return block
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def txn_hash_with_log(geth_fixture_data):
     return geth_fixture_data["txn_hash_with_log"]
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def block_hash_revert_no_msg(geth_fixture_data):
     return geth_fixture_data["block_hash_revert_no_msg"]
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def block_hash_revert_with_msg(geth_fixture_data):
     return geth_fixture_data["block_hash_revert_with_msg"]
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def revert_contract(revert_contract_factory, geth_fixture_data):
     return revert_contract_factory(address=geth_fixture_data["revert_address"])
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def offchain_lookup_contract(offchain_lookup_contract_factory, geth_fixture_data):
     return offchain_lookup_contract_factory(
         address=geth_fixture_data["offchain_lookup_address"]
     )
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def panic_errors_contract(
     w3,
     geth_fixture_data,
@@ -267,7 +285,7 @@ def panic_errors_contract(
     return contract_factory(address=geth_fixture_data["panic_errors_contract_address"])
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def storage_contract(
     w3,
     geth_fixture_data,
@@ -279,19 +297,19 @@ def storage_contract(
 # --- async --- #
 
 
-@pytest_asyncio.fixture(scope="module")
+@pytest_asyncio.fixture
 async def async_keyfile_account_address(geth_fixture_data):
     return geth_fixture_data["keyfile_account_address"]
 
 
-@pytest_asyncio.fixture(scope="module")
+@pytest_asyncio.fixture
 async def async_keyfile_account_address_dual_type(
     async_keyfile_account_address, address_conversion_func
 ):
     yield async_keyfile_account_address
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def async_offchain_lookup_contract(
     async_offchain_lookup_contract_factory, geth_fixture_data
 ):
@@ -300,7 +318,7 @@ def async_offchain_lookup_contract(
     )
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def async_panic_errors_contract(
     async_w3,
     geth_fixture_data,
@@ -309,35 +327,35 @@ def async_panic_errors_contract(
     return contract_factory(address=geth_fixture_data["panic_errors_contract_address"])
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def async_emitter_contract(async_w3, geth_fixture_data):
     contract_factory = async_w3.eth.contract(**EMITTER_CONTRACT_DATA)
     return contract_factory(address=geth_fixture_data["emitter_address"])
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def async_emitter_contract_address(async_emitter_contract, address_conversion_func):
     return address_conversion_func(async_emitter_contract.address)
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def async_math_contract(async_w3, geth_fixture_data):
     contract_factory = async_w3.eth.contract(**MATH_CONTRACT_DATA)
     return contract_factory(address=geth_fixture_data["math_address"])
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def async_math_contract_address(async_math_contract, address_conversion_func):
     return address_conversion_func(async_math_contract.address)
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def async_revert_contract(async_w3, geth_fixture_data):
     contract_factory = async_w3.eth.contract(**REVERT_CONTRACT_DATA)
     return contract_factory(address=geth_fixture_data["revert_address"])
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def async_storage_contract(
     async_w3,
     geth_fixture_data,
@@ -346,21 +364,21 @@ def async_storage_contract(
     return contract_factory(address=geth_fixture_data["storage_contract_address"])
 
 
-@pytest_asyncio.fixture(scope="module")
+@pytest_asyncio.fixture
 async def async_empty_block(async_w3, geth_fixture_data):
     block = await async_w3.eth.get_block(geth_fixture_data["empty_block_hash"])
     assert is_dict(block)
     return block
 
 
-@pytest_asyncio.fixture(scope="module")
+@pytest_asyncio.fixture
 async def async_block_with_txn(async_w3, geth_fixture_data):
     block = await async_w3.eth.get_block(geth_fixture_data["block_with_txn_hash"])
     assert is_dict(block)
     return block
 
 
-@pytest_asyncio.fixture(scope="module")
+@pytest_asyncio.fixture
 async def async_block_with_txn_with_log(async_w3, geth_fixture_data):
     block = await async_w3.eth.get_block(geth_fixture_data["block_hash_with_log"])
     assert is_dict(block)
diff --git a/tests/integration/go_ethereum/test_goethereum_http.py b/tests/integration/go_ethereum/test_goethereum_http.py
index 0415b27a9a..8cd9935e8a 100644
--- a/tests/integration/go_ethereum/test_goethereum_http.py
+++ b/tests/integration/go_ethereum/test_goethereum_http.py
@@ -5,9 +5,6 @@
 )
 import pytest_asyncio
 
-from tests.utils import (
-    get_open_port,
-)
 from web3 import (
     AsyncWeb3,
     Web3,
@@ -32,29 +29,15 @@
     GoEthereumTxPoolModuleTest,
     GoEthereumWeb3ModuleTest,
 )
-from .utils import (
-    wait_for_aiohttp,
-    wait_for_http,
-)
-
-
-@pytest.fixture(scope="module")
-def rpc_port():
-    return get_open_port()
 
 
-@pytest.fixture(scope="module")
-def endpoint_uri(rpc_port):
-    return f"http://localhost:{rpc_port}"
-
-
-def _geth_command_arguments(rpc_port, base_geth_command_arguments, geth_version):
+def _geth_command_arguments(base_geth_command_arguments, geth_version):
     yield from base_geth_command_arguments
     if geth_version.major == 1:
         yield from (
             "--http",
             "--http.port",
-            rpc_port,
+            "0",
             "--http.api",
             "admin,debug,eth,net,web3,txpool",
             "--ipcdisable",
@@ -63,27 +46,29 @@ def _geth_command_arguments(rpc_port, base_geth_command_arguments, geth_version)
         raise AssertionError("Unsupported Geth version")
 
 
-@pytest.fixture(scope="module")
-def geth_command_arguments(rpc_port, base_geth_command_arguments, get_geth_version):
-    return _geth_command_arguments(
-        rpc_port, base_geth_command_arguments, get_geth_version
-    )
+@pytest.fixture
+def geth_command_arguments(base_geth_command_arguments, get_geth_version):
+    return _geth_command_arguments(base_geth_command_arguments, get_geth_version)
 
 
-@pytest.fixture(scope="module")
-def w3(geth_process, endpoint_uri):
-    wait_for_http(endpoint_uri)
-    return Web3(Web3.HTTPProvider(endpoint_uri, request_kwargs={"timeout": 10}))
-
+@pytest.fixture
+def w3(start_geth_process_and_yield_port):
+    port = start_geth_process_and_yield_port
+    _w3 = Web3(
+        Web3.HTTPProvider(f"http://127.0.0.1:{port}", request_kwargs={"timeout": 10})
+    )
+    return _w3
 
-@pytest.fixture(scope="module")
-def auto_w3(geth_process, endpoint_uri):
-    wait_for_http(endpoint_uri)
 
+@pytest.fixture
+def auto_w3(start_geth_process_and_yield_port, monkeypatch):
     from web3.auto import (
         w3,
     )
 
+    port = start_geth_process_and_yield_port
+    monkeypatch.setenv("WEB3_PROVIDER_URI", f"http://127.0.0.1:{port}")
+
     return w3
 
 
@@ -116,13 +101,7 @@ class TestGoEthereumDebugModuleTest(GoEthereumDebugModuleTest):
 
 
 class TestGoEthereumEthModuleTest(GoEthereumEthModuleTest):
-    def test_auto_provider_batching(
-        self,
-        auto_w3: "Web3",
-        monkeypatch,
-        endpoint_uri,
-    ) -> None:
-        monkeypatch.setenv("WEB3_PROVIDER_URI", endpoint_uri)
+    def test_auto_provider_batching(self, auto_w3: "Web3") -> None:
         # test that batch_requests doesn't error out when using the auto provider
         auto_w3.batch_requests()
 
@@ -138,13 +117,16 @@ class TestGoEthereumTxPoolModuleTest(GoEthereumTxPoolModuleTest):
 # -- async -- #
 
 
-@pytest_asyncio.fixture(scope="module")
-async def async_w3(geth_process, endpoint_uri):
-    await wait_for_aiohttp(endpoint_uri)
+@pytest_asyncio.fixture
+async def async_w3(start_geth_process_and_yield_port):
+    port = start_geth_process_and_yield_port
     _w3 = AsyncWeb3(
-        AsyncHTTPProvider(endpoint_uri, request_kwargs={"timeout": ClientTimeout(10)})
+        AsyncHTTPProvider(
+            f"http://127.0.0.1:{port}", request_kwargs={"timeout": ClientTimeout(10)}
+        )
     )
-    return _w3
+    yield _w3
+    await _w3.provider.disconnect()
 
 
 class TestGoEthereumAsyncWeb3ModuleTest(GoEthereumAsyncWeb3ModuleTest):
@@ -184,12 +166,10 @@ class TestGoEthereumAsyncNetModuleTest(GoEthereumAsyncNetModuleTest):
 
 class TestGoEthereumAsyncEthModuleTest(GoEthereumAsyncEthModuleTest):
     @pytest.mark.asyncio
-    async def test_async_http_provider_disconnects_gracefully(
-        self, async_w3, endpoint_uri
-    ) -> None:
+    async def test_async_http_provider_disconnects_gracefully(self, async_w3) -> None:
         w3_1 = async_w3
 
-        w3_2 = AsyncWeb3(AsyncHTTPProvider(endpoint_uri))
+        w3_2 = AsyncWeb3(AsyncHTTPProvider(async_w3.provider.endpoint_uri))
         assert w3_1 != w3_2
 
         await w3_1.eth.get_block("latest")
diff --git a/tests/integration/go_ethereum/test_goethereum_ipc.py b/tests/integration/go_ethereum/test_goethereum_ipc.py
index c495f5feac..7e52633cb4 100644
--- a/tests/integration/go_ethereum/test_goethereum_ipc.py
+++ b/tests/integration/go_ethereum/test_goethereum_ipc.py
@@ -38,12 +38,12 @@ def _geth_command_arguments(geth_ipc_path, base_geth_command_arguments):
     )
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def geth_command_arguments(geth_ipc_path, base_geth_command_arguments):
     return _geth_command_arguments(geth_ipc_path, base_geth_command_arguments)
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def geth_ipc_path(datadir):
     geth_ipc_dir_path = tempfile.mkdtemp()
     _geth_ipc_path = os.path.join(geth_ipc_dir_path, "geth.ipc")
@@ -53,19 +53,20 @@ def geth_ipc_path(datadir):
         os.remove(_geth_ipc_path)
 
 
-@pytest.fixture(scope="module")
-def auto_w3(geth_process, geth_ipc_path):
-    wait_for_socket(geth_ipc_path)
-
+@pytest.fixture
+def auto_w3(start_geth_process_and_yield_port, geth_ipc_path, monkeypatch):
     from web3.auto import (
         w3,
     )
 
+    wait_for_socket(geth_ipc_path)
+    monkeypatch.setenv("WEB3_PROVIDER_URI", f"file:///{geth_ipc_path}")
+
     return w3
 
 
-@pytest.fixture(scope="module")
-def w3(geth_process, geth_ipc_path):
+@pytest.fixture
+def w3(start_geth_process_and_yield_port, geth_ipc_path):
     wait_for_socket(geth_ipc_path)
     return Web3(Web3.IPCProvider(geth_ipc_path, timeout=10))
 
@@ -79,13 +80,7 @@ class TestGoEthereumDebugModuleTest(GoEthereumDebugModuleTest):
 
 
 class TestGoEthereumEthModuleTest(GoEthereumEthModuleTest):
-    def test_auto_provider_batching(
-        self,
-        auto_w3: "Web3",
-        monkeypatch,
-        geth_ipc_path,
-    ) -> None:
-        monkeypatch.setenv("WEB3_PROVIDER_URI", f"file:///{geth_ipc_path}")
+    def test_auto_provider_batching(self, auto_w3: "Web3") -> None:
         # test that batch_requests doesn't error out when using the auto provider
         auto_w3.batch_requests()
 
@@ -117,8 +112,8 @@ def test_admin_start_stop_ws(self, w3: "Web3") -> None:
 # -- async -- #
 
 
-@pytest_asyncio.fixture(scope="module")
-async def async_w3(geth_process, geth_ipc_path):
+@pytest_asyncio.fixture
+async def async_w3(start_geth_process_and_yield_port, geth_ipc_path):
     await wait_for_async_socket(geth_ipc_path)
     async with AsyncWeb3(AsyncIPCProvider(geth_ipc_path, request_timeout=10)) as _aw3:
         yield _aw3
diff --git a/tests/integration/go_ethereum/test_goethereum_legacy_ws.py b/tests/integration/go_ethereum/test_goethereum_legacy_ws.py
index e979159a92..31f7c1914a 100644
--- a/tests/integration/go_ethereum/test_goethereum_legacy_ws.py
+++ b/tests/integration/go_ethereum/test_goethereum_legacy_ws.py
@@ -1,14 +1,9 @@
 import pytest
-import asyncio
 
 from tests.integration.common import (
     COINBASE,
     MiscWebSocketTest,
 )
-from tests.utils import (
-    get_open_port,
-    wait_for_ws,
-)
 from web3 import (
     Web3,
 )
@@ -22,17 +17,7 @@
 )
 
 
-@pytest.fixture(scope="module")
-def ws_port():
-    return get_open_port()
-
-
-@pytest.fixture(scope="module")
-def endpoint_uri(ws_port):
-    return f"ws://localhost:{ws_port}"
-
-
-def _geth_command_arguments(ws_port, base_geth_command_arguments, geth_version):
+def _geth_command_arguments(base_geth_command_arguments, geth_version):
     yield from base_geth_command_arguments
     if geth_version.major == 1:
         yield from (
@@ -40,7 +25,7 @@ def _geth_command_arguments(ws_port, base_geth_command_arguments, geth_version):
             COINBASE[2:],
             "--ws",
             "--ws.port",
-            ws_port,
+            "0",
             "--ws.api",
             "admin,debug,eth,net,web3",
             "--ws.origins",
@@ -55,19 +40,17 @@ def _geth_command_arguments(ws_port, base_geth_command_arguments, geth_version):
         raise AssertionError("Unsupported Geth version")
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def geth_command_arguments(
-    geth_binary, get_geth_version, datadir, ws_port, base_geth_command_arguments
+    geth_binary, get_geth_version, datadir, base_geth_command_arguments
 ):
-    return _geth_command_arguments(
-        ws_port, base_geth_command_arguments, get_geth_version
-    )
+    return _geth_command_arguments(base_geth_command_arguments, get_geth_version)
 
 
-@pytest.fixture(scope="module")
-def w3(geth_process, endpoint_uri):
-    event_loop = asyncio.new_event_loop()
-    event_loop.run_until_complete(wait_for_ws(endpoint_uri))
+@pytest.fixture
+def w3(start_geth_process_and_yield_port):
+    port = start_geth_process_and_yield_port
+    endpoint_uri = f"ws://127.0.0.1:{port}"
     _w3 = Web3(Web3.LegacyWebSocketProvider(endpoint_uri, websocket_timeout=30))
     return _w3
 
diff --git a/tests/integration/go_ethereum/test_goethereum_ws/conftest.py b/tests/integration/go_ethereum/test_goethereum_ws/conftest.py
index 7f9d684145..007aaed0ab 100644
--- a/tests/integration/go_ethereum/test_goethereum_ws/conftest.py
+++ b/tests/integration/go_ethereum/test_goethereum_ws/conftest.py
@@ -3,22 +3,9 @@
 from tests.integration.common import (
     COINBASE,
 )
-from tests.utils import (
-    get_open_port,
-)
-
-
-@pytest.fixture(scope="module")
-def ws_port():
-    return get_open_port()
-
-
-@pytest.fixture(scope="module")
-def endpoint_uri(ws_port):
-    return f"ws://localhost:{ws_port}"
 
 
-def _geth_command_arguments(ws_port, base_geth_command_arguments, geth_version):
+def _geth_command_arguments(base_geth_command_arguments, geth_version):
     yield from base_geth_command_arguments
     if geth_version.major == 1:
         yield from (
@@ -26,7 +13,7 @@ def _geth_command_arguments(ws_port, base_geth_command_arguments, geth_version):
             COINBASE[2:],
             "--ws",
             "--ws.port",
-            ws_port,
+            "0",
             "--ws.api",
             "admin,debug,eth,net,web3",
             "--ws.origins",
@@ -40,10 +27,8 @@ def _geth_command_arguments(ws_port, base_geth_command_arguments, geth_version):
         raise AssertionError("Unsupported Geth version")
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def geth_command_arguments(
-    geth_binary, get_geth_version, datadir, ws_port, base_geth_command_arguments
+    geth_binary, get_geth_version, datadir, base_geth_command_arguments
 ):
-    return _geth_command_arguments(
-        ws_port, base_geth_command_arguments, get_geth_version
-    )
+    return _geth_command_arguments(base_geth_command_arguments, get_geth_version)
diff --git a/tests/integration/go_ethereum/test_goethereum_ws/test_async_await_w3.py b/tests/integration/go_ethereum/test_goethereum_ws/test_async_await_w3.py
index e491d92f37..ce5bffa35d 100644
--- a/tests/integration/go_ethereum/test_goethereum_ws/test_async_await_w3.py
+++ b/tests/integration/go_ethereum/test_goethereum_ws/test_async_await_w3.py
@@ -19,16 +19,17 @@
     GoEthereumAsyncNetModuleTest,
     GoEthereumAsyncWeb3ModuleTest,
 )
-from ..utils import (
-    wait_for_aiohttp,
-)
 
 
-@pytest_asyncio.fixture(scope="module")
-async def async_w3(geth_process, endpoint_uri):
-    await wait_for_aiohttp(endpoint_uri)
+@pytest_asyncio.fixture
+async def async_w3(start_geth_process_and_yield_port):
+    port = start_geth_process_and_yield_port
     # await the persistent connection itself
-    return await AsyncWeb3(WebSocketProvider(endpoint_uri, request_timeout=10))
+    _async_w3 = await AsyncWeb3(
+        WebSocketProvider(f"ws://127.0.0.1:{port}", request_timeout=10)
+    )
+    yield _async_w3
+    await _async_w3.provider.disconnect()
 
 
 class TestGoEthereumAsyncWeb3ModuleTest(GoEthereumAsyncWeb3ModuleTest):
diff --git a/tests/integration/go_ethereum/test_goethereum_ws/test_async_ctx_manager_w3.py b/tests/integration/go_ethereum/test_goethereum_ws/test_async_ctx_manager_w3.py
index 7187dbf4c3..f07723f4b8 100644
--- a/tests/integration/go_ethereum/test_goethereum_ws/test_async_ctx_manager_w3.py
+++ b/tests/integration/go_ethereum/test_goethereum_ws/test_async_ctx_manager_w3.py
@@ -19,16 +19,15 @@
     GoEthereumAsyncNetModuleTest,
     GoEthereumAsyncWeb3ModuleTest,
 )
-from ..utils import (
-    wait_for_aiohttp,
-)
 
 
-@pytest_asyncio.fixture(scope="module")
-async def async_w3(geth_process, endpoint_uri):
-    await wait_for_aiohttp(endpoint_uri)
+@pytest_asyncio.fixture
+async def async_w3(start_geth_process_and_yield_port):
+    port = start_geth_process_and_yield_port
     # async context manager pattern
-    async with AsyncWeb3(WebSocketProvider(endpoint_uri, request_timeout=10)) as w3:
+    async with AsyncWeb3(
+        WebSocketProvider(f"ws://127.0.0.1:{port}", request_timeout=10)
+    ) as w3:
         yield w3
 
 
diff --git a/tests/integration/go_ethereum/test_goethereum_ws/test_async_iterator_w3.py b/tests/integration/go_ethereum/test_goethereum_ws/test_async_iterator_w3.py
index 5e80702d1e..31fbca6858 100644
--- a/tests/integration/go_ethereum/test_goethereum_ws/test_async_iterator_w3.py
+++ b/tests/integration/go_ethereum/test_goethereum_ws/test_async_iterator_w3.py
@@ -19,17 +19,18 @@
     GoEthereumAsyncNetModuleTest,
     GoEthereumAsyncWeb3ModuleTest,
 )
-from ..utils import (
-    wait_for_aiohttp,
-)
 
 
-@pytest_asyncio.fixture(scope="module")
-async def async_w3(geth_process, endpoint_uri):
-    await wait_for_aiohttp(endpoint_uri)
+@pytest_asyncio.fixture
+async def async_w3(start_geth_process_and_yield_port):
+    port = start_geth_process_and_yield_port
+    endpoint_uri = f"ws://127.0.0.1:{port}"
     # async iterator pattern
     async for w3 in AsyncWeb3(WebSocketProvider(endpoint_uri, request_timeout=10)):
-        return w3
+        yield w3
+        # we won't be iterating to the next w3 instance, so disconnect explicitly
+        await w3.provider.disconnect()
+        break
 
 
 class TestGoEthereumAsyncWeb3ModuleTest(GoEthereumAsyncWeb3ModuleTest):
diff --git a/tests/integration/go_ethereum/utils.py b/tests/integration/go_ethereum/utils.py
index a9842a8131..2cf92915b7 100644
--- a/tests/integration/go_ethereum/utils.py
+++ b/tests/integration/go_ethereum/utils.py
@@ -3,9 +3,6 @@
 import socket
 import time
 
-import aiohttp
-import requests
-
 
 def wait_for_socket(ipc_path, timeout=30):
     start = time.time()
@@ -32,29 +29,6 @@ async def wait_for_async_socket(ipc_path, timeout=30):
             break
 
 
-def wait_for_http(endpoint_uri, timeout=60):
-    start = time.time()
-    while time.time() < start + timeout:
-        try:
-            requests.get(endpoint_uri)
-        except requests.ConnectionError:
-            time.sleep(0.01)
-        else:
-            break
-
-
-async def wait_for_aiohttp(endpoint_uri, timeout=60):
-    start = time.time()
-    while time.time() < start + timeout:
-        try:
-            async with aiohttp.ClientSession() as session:
-                await session.get(endpoint_uri)
-        except aiohttp.client_exceptions.ClientConnectorError:
-            time.sleep(0.01)
-        else:
-            break
-
-
 def wait_for_popen(proc, timeout):
     start = time.time()
     while time.time() < start + timeout:
diff --git a/tests/integration/test_ethereum_tester.py b/tests/integration/test_ethereum_tester.py
index 2664b236ed..153c66cfbb 100644
--- a/tests/integration/test_ethereum_tester.py
+++ b/tests/integration/test_ethereum_tester.py
@@ -68,13 +68,13 @@ def _deploy_contract(w3, contract_factory):
     return contract_factory(contract_address)
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def eth_tester():
     _eth_tester = EthereumTester()
     return _eth_tester
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def eth_tester_provider(eth_tester):
     provider = EthereumTesterProvider(eth_tester)
     return provider
@@ -96,7 +96,7 @@ def _eth_tester_state_setup(w3):
     )
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def w3(eth_tester_provider):
     _w3 = Web3(eth_tester_provider)
     _w3.eth.default_account = _w3.eth.accounts[0]
@@ -104,7 +104,7 @@ def w3(eth_tester_provider):
     return _w3
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def math_contract_deploy_txn_hash(w3, math_contract_factory):
     deploy_txn_hash = math_contract_factory.constructor().transact(
         {"from": w3.eth.default_account}
@@ -112,7 +112,7 @@ def math_contract_deploy_txn_hash(w3, math_contract_factory):
     return deploy_txn_hash
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def math_contract(w3, math_contract_factory, math_contract_deploy_txn_hash):
     deploy_receipt = w3.eth.wait_for_transaction_receipt(math_contract_deploy_txn_hash)
     assert is_dict(deploy_receipt)
@@ -121,28 +121,28 @@ def math_contract(w3, math_contract_factory, math_contract_deploy_txn_hash):
     return math_contract_factory(contract_address)
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def math_contract_address(math_contract, address_conversion_func):
     return address_conversion_func(math_contract.address)
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def storage_contract(w3):
     contract_factory = w3.eth.contract(**STORAGE_CONTRACT_DATA)
     return _deploy_contract(w3, contract_factory)
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def emitter_contract(w3, emitter_contract_factory):
     return _deploy_contract(w3, emitter_contract_factory)
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def emitter_contract_address(emitter_contract, address_conversion_func):
     return address_conversion_func(emitter_contract.address)
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def empty_block(w3):
     w3.testing.mine()
     block = w3.eth.get_block("latest")
@@ -150,7 +150,7 @@ def empty_block(w3):
     return block
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def block_with_txn(w3):
     txn_hash = w3.eth.send_transaction(
         {
@@ -168,12 +168,12 @@ def block_with_txn(w3):
     return block
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def mined_txn_hash(block_with_txn):
     return block_with_txn["transactions"][0]
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def block_with_txn_with_log(w3, emitter_contract):
     txn_hash = emitter_contract.functions.logDouble(
         which=EMITTER_ENUM["LogDoubleWithIndex"],
@@ -185,12 +185,12 @@ def block_with_txn_with_log(w3, emitter_contract):
     return block
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def txn_hash_with_log(block_with_txn_with_log):
     return block_with_txn_with_log["transactions"][0]
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def revert_contract(w3, revert_contract_factory):
     return _deploy_contract(w3, revert_contract_factory)
 
@@ -198,23 +198,23 @@ def revert_contract(w3, revert_contract_factory):
 #
 # Offchain Lookup Contract Setup
 #
-@pytest.fixture(scope="module")
+@pytest.fixture
 def offchain_lookup_contract(w3, offchain_lookup_contract_factory):
     return _deploy_contract(w3, offchain_lookup_contract_factory)
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def panic_errors_contract(w3):
     panic_errors_contract_factory = w3.eth.contract(**PANIC_ERRORS_CONTRACT_DATA)
     return _deploy_contract(w3, panic_errors_contract_factory)
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def keyfile_account_pkey():
     yield KEYFILE_ACCOUNT_PKEY
 
 
-@pytest.fixture(scope="module")
+@pytest.fixture
 def keyfile_account_address():
     yield KEYFILE_ACCOUNT_ADDRESS
 
diff --git a/tests/utils.py b/tests/utils.py
index 3aac726ba3..4779d33658 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -2,6 +2,9 @@
 import socket
 import time
 
+from websockets import (
+    WebSocketException,
+)
 from websockets.legacy.client import (
     connect,
 )
@@ -45,12 +48,24 @@ async def wait_for_ws(endpoint_uri, timeout=10):
     start = time.time()
     while time.time() < start + timeout:
         try:
-            async with connect(uri=endpoint_uri):
-                pass
-        except OSError:
-            await asyncio.sleep(0.01)
-        else:
-            break
+            async with connect(uri=endpoint_uri) as ws:
+                await ws.send(
+                    '{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":1}'
+                )
+                r = await ws.recv()
+                if isinstance(r, bytes):
+                    r = r.decode("utf-8")
+
+                if "geth" in r.lower():
+                    return
+        except (OSError, WebSocketException):
+            pass
+        except Exception:
+            raise
+        await asyncio.sleep(0.01)
+    raise TimeoutError(
+        f"Geth WebSocket did not respond on {endpoint_uri} within {timeout} seconds."
+    )
 
 
 async def _async_wait_for_block_fixture_logic(async_w3, block_number=1, timeout=None):
diff --git a/tox.ini b/tox.ini
index b02cbd69b4..cc74b5e199 100644
--- a/tox.ini
+++ b/tox.ini
@@ -22,15 +22,15 @@ usedevelop=True
 commands=
     core: pytest {posargs:tests/core -m "not asyncio"}
     core_async: pytest {posargs:tests/core -m asyncio}
-    ens: pytest {posargs:tests/ens --ignore=tests/ens/normalization/test_normalize_name_ensip15.py}
-    ensip15: pytest {posargs:tests/ens/normalization/test_normalize_name_ensip15.py -q}
-    integration-goethereum-ipc: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ipc.py -k "not Async"}
-    integration-goethereum-ipc_async: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ipc.py -k Async}
-    integration-goethereum-http: pytest {posargs:tests/integration/go_ethereum/test_goethereum_http.py -k "not Async"}
-    integration-goethereum-http_async: pytest {posargs:tests/integration/go_ethereum/test_goethereum_http.py -k Async}
-    integration-goethereum-legacy_ws: pytest {posargs:tests/integration/go_ethereum/test_goethereum_legacy_ws.py}
-    integration-goethereum-ws: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ws}
-    integration-ethtester: pytest {posargs:tests/integration/test_ethereum_tester.py}
+    ens: pytest {posargs:tests/ens --ignore=tests/ens/normalization/test_normalize_name_ensip15.py -n auto --maxprocesses=15}
+    ensip15: pytest {posargs:tests/ens/normalization/test_normalize_name_ensip15.py -q -n auto --maxprocesses=15}
+    integration-goethereum-ipc: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ipc.py -k "not Async" -n auto --maxprocesses=15}
+    integration-goethereum-ipc_async: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ipc.py -k Async -n auto --maxprocesses=15}
+    integration-goethereum-http: pytest {posargs:tests/integration/go_ethereum/test_goethereum_http.py -k "not Async" -n auto --maxprocesses=15}
+    integration-goethereum-http_async: pytest {posargs:tests/integration/go_ethereum/test_goethereum_http.py -k Async -n auto --maxprocesses=15}
+    integration-goethereum-legacy_ws: pytest {posargs:tests/integration/go_ethereum/test_goethereum_legacy_ws.py -n auto --maxprocesses=15}
+    integration-goethereum-ws: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ws -n auto --maxprocesses=15}
+    integration-ethtester: pytest {posargs:tests/integration/test_ethereum_tester.py -n auto --maxprocesses=15}
     docs: make check-docs-ci
 deps =
     .[test]
diff --git a/web3/_utils/encoding.py b/web3/_utils/encoding.py
index 74d13b8cb2..b08e887ff2 100644
--- a/web3/_utils/encoding.py
+++ b/web3/_utils/encoding.py
@@ -36,6 +36,9 @@
 from hexbytes import (
     HexBytes,
 )
+from pydantic import (
+    BaseModel,
+)
 
 from web3._utils.abi import (
     is_address_type,
@@ -299,6 +302,11 @@ def default(self, obj: Any) -> Union[Dict[Any, Any], HexStr]:
             return obj.__dict__
         elif isinstance(obj, (HexBytes, bytes)):
             return to_hex(obj)
+        elif isinstance(obj, BaseModel):
+            # TODO: For now we can assume all BaseModel objects behave this way, but
+            #  internally we will start to use the CamelModel from eth-utils. Perhaps
+            #  we should check for that type instead.
+            return obj.model_dump(by_alias=True)
         return json.JSONEncoder.default(self, obj)
 
 
diff --git a/web3/_utils/method_formatters.py b/web3/_utils/method_formatters.py
index 71f27e1970..09444811c7 100644
--- a/web3/_utils/method_formatters.py
+++ b/web3/_utils/method_formatters.py
@@ -47,6 +47,9 @@
 from hexbytes import (
     HexBytes,
 )
+from pydantic import (
+    BaseModel,
+)
 
 from web3._utils.abi import (
     is_length,
@@ -161,6 +164,12 @@ def type_aware_apply_formatters_to_dict(
     """
     Preserve ``AttributeDict`` types if original ``value`` was an ``AttributeDict``.
     """
+    # TODO: In v8, Use eth-utils 5.3.0 as lower pin where ``apply_formatters_to_dict``
+    #  already handles the CamelModel case, rather than generalizing to all BaseModel
+    #  instances.
+    if isinstance(value, BaseModel):
+        value = value.model_dump(by_alias=True)
+
     formatted_dict: Dict[str, Any] = apply_formatters_to_dict(formatters, dict(value))
     return (
         AttributeDict.recursive(formatted_dict)
@@ -177,6 +186,9 @@ def type_aware_apply_formatters_to_dict_keys_and_values(
     """
     Preserve ``AttributeDict`` types if original ``value`` was an ``AttributeDict``.
     """
+    if isinstance(dict_like_object, BaseModel):
+        dict_like_object = dict_like_object.model_dump(by_alias=True)
+
     formatted_dict = {
         key_formatters(k): value_formatters(v) for k, v in dict_like_object.items()
     }
@@ -223,6 +235,22 @@ def storage_key_to_hexstr(value: Union[bytes, int, str]) -> HexStr:
     }
 )
 
+AUTH_LIST_RESULT_FORMATTER = apply_formatter_if(
+    is_not_null,
+    apply_formatter_to_array(
+        type_aware_apply_formatters_to_dict(
+            {
+                "chainId": to_integer_if_hex,
+                "address": to_checksum_address,
+                "nonce": to_integer_if_hex,
+                "yParity": to_integer_if_hex,
+                "r": to_hexbytes(32, variable_length=True),
+                "s": to_hexbytes(32, variable_length=True),
+            }
+        ),
+    ),
+)
+
 TRANSACTION_RESULT_FORMATTERS = {
     "blockHash": apply_formatter_if(is_not_null, to_hexbytes(32)),
     "blockNumber": apply_formatter_if(is_not_null, to_integer_if_hex),
@@ -255,6 +283,7 @@ def storage_key_to_hexstr(value: Union[bytes, int, str]) -> HexStr:
     "blobVersionedHashes": apply_formatter_if(
         is_not_null, apply_formatter_to_array(to_hexbytes(32))
     ),
+    "authorizationList": AUTH_LIST_RESULT_FORMATTER,
 }
 
 
@@ -332,6 +361,7 @@ def storage_key_to_hexstr(value: Union[bytes, int, str]) -> HexStr:
     "transactionsRoot": to_hex_if_bytes,
     "withdrawalsRoot": to_hex_if_bytes,
     "parentBeaconBlockRoot": to_hex_if_bytes,
+    "requestsHash": to_hex_if_bytes,
 }
 block_request_formatter = type_aware_apply_formatters_to_dict(BLOCK_REQUEST_FORMATTERS)
 
@@ -374,6 +404,7 @@ def storage_key_to_hexstr(value: Union[bytes, int, str]) -> HexStr:
     "blobGasUsed": to_integer_if_hex,
     "excessBlobGas": to_integer_if_hex,
     "parentBeaconBlockRoot": apply_formatter_if(is_not_null, to_hexbytes(32)),
+    "requestsHash": apply_formatter_if(is_not_null, to_hexbytes(32)),
 }
 block_result_formatter = type_aware_apply_formatters_to_dict(BLOCK_RESULT_FORMATTERS)
 
@@ -466,6 +497,22 @@ def storage_key_to_hexstr(value: Union[bytes, int, str]) -> HexStr:
     )
 )
 
+AUTH_LIST_REQUEST_FORMATTER = apply_formatter_if(
+    is_not_null,
+    apply_formatter_to_array(
+        type_aware_apply_formatters_to_dict(
+            {
+                "chainId": to_hex_if_integer,
+                "address": to_checksum_address,
+                "nonce": to_hex_if_integer,
+                "yParity": to_hex_if_integer,
+                "r": to_hex_if_integer,
+                "s": to_hex_if_integer,
+            }
+        ),
+    ),
+)
+
 TRANSACTION_REQUEST_FORMATTER = {
     "from": to_checksum_address,
     "to": apply_formatter_if(is_address, to_checksum_address),
@@ -477,12 +524,13 @@ def storage_key_to_hexstr(value: Union[bytes, int, str]) -> HexStr:
     "maxFeePerGas": to_hex_if_integer,
     "maxPriorityFeePerGas": to_hex_if_integer,
     "chainId": to_hex_if_integer,
+    "authorizationList": AUTH_LIST_REQUEST_FORMATTER,
 }
 transaction_request_formatter = type_aware_apply_formatters_to_dict(
     TRANSACTION_REQUEST_FORMATTER
 )
 
-ACCESS_LIST_REQUEST_FORMATTER = type_aware_apply_formatters_to_dict(
+ETH_CALL_TX_FORMATTER = type_aware_apply_formatters_to_dict(
     {
         "accessList": apply_formatter_if(
             is_not_null,
@@ -494,10 +542,11 @@ def storage_key_to_hexstr(value: Union[bytes, int, str]) -> HexStr:
                 )
             ),
         ),
+        "authorizationList": AUTH_LIST_REQUEST_FORMATTER,
     }
 )
 transaction_param_formatter = compose(
-    ACCESS_LIST_REQUEST_FORMATTER,
+    ETH_CALL_TX_FORMATTER,
     remove_key_if("to", lambda txn: txn["to"] in {"", b"", None}),
     remove_key_if("gasPrice", lambda txn: txn["gasPrice"] in {"", b"", None}),
 )
@@ -1057,7 +1106,7 @@ def combine_formatters(
 
 
 def get_request_formatters(
-    method_name: Union[RPCEndpoint, Callable[..., RPCEndpoint]]
+    method_name: Union[RPCEndpoint, Callable[..., RPCEndpoint]],
 ) -> Dict[str, Callable[..., Any]]:
     request_formatter_maps = (
         ABI_REQUEST_FORMATTERS,
@@ -1083,7 +1132,7 @@ def raise_block_not_found(params: Tuple[BlockIdentifier, bool]) -> NoReturn:
 
 
 def raise_block_not_found_for_uncle_at_index(
-    params: Tuple[BlockIdentifier, Union[HexStr, int]]
+    params: Tuple[BlockIdentifier, Union[HexStr, int]],
 ) -> NoReturn:
     try:
         block_identifier = params[0]
@@ -1109,7 +1158,7 @@ def raise_transaction_not_found(params: Tuple[_Hash32]) -> NoReturn:
 
 
 def raise_transaction_not_found_with_index(
-    params: Tuple[BlockIdentifier, int]
+    params: Tuple[BlockIdentifier, int],
 ) -> NoReturn:
     try:
         block_identifier = params[0]
@@ -1213,7 +1262,7 @@ def get_result_formatters(
 
 
 def get_error_formatters(
-    method_name: Union[RPCEndpoint, Callable[..., RPCEndpoint]]
+    method_name: Union[RPCEndpoint, Callable[..., RPCEndpoint]],
 ) -> Callable[..., Any]:
     #  Note error formatters work on the full response dict
     error_formatter_maps = (ERROR_FORMATTERS,)
@@ -1223,7 +1272,7 @@ def get_error_formatters(
 
 
 def get_null_result_formatters(
-    method_name: Union[RPCEndpoint, Callable[..., RPCEndpoint]]
+    method_name: Union[RPCEndpoint, Callable[..., RPCEndpoint]],
 ) -> Callable[..., Any]:
     formatters = combine_formatters((NULL_RESULT_FORMATTERS,), method_name)
 
diff --git a/web3/_utils/module_testing/eth_module.py b/web3/_utils/module_testing/eth_module.py
index 52950d76eb..bc5abe34f0 100644
--- a/web3/_utils/module_testing/eth_module.py
+++ b/web3/_utils/module_testing/eth_module.py
@@ -57,7 +57,6 @@
 from web3._utils.module_testing.module_testing_utils import (
     assert_contains_log,
     async_mock_offchain_lookup_request_response,
-    flaky_geth_dev_mining,
     mock_offchain_lookup_request_response,
 )
 from web3._utils.module_testing.utils import (
@@ -115,27 +114,6 @@
 # "web3py" as an abi-encoded string
 WEB3PY_AS_HEXBYTES = "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000067765623370790000000000000000000000000000000000000000000000000000"  # noqa: E501
 
-RLP_ACCESS_LIST = [
-    (
-        "0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae",
-        (
-            "0x0000000000000000000000000000000000000000000000000000000000000003",
-            "0x0000000000000000000000000000000000000000000000000000000000000007",
-        ),
-    ),
-    ("0xbb9bc244d798123fde783fcc1c72d3bb8c189413", ()),
-]
-
-RPC_ACCESS_LIST = [
-    {
-        "address": "0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae",
-        "storageKeys": (
-            "0x0000000000000000000000000000000000000000000000000000000000000003",
-            "0x0000000000000000000000000000000000000000000000000000000000000007",
-        ),
-    },
-    {"address": "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", "storageKeys": ()},
-]
 
 if TYPE_CHECKING:
     from _pytest.monkeypatch import MonkeyPatch  # noqa: F401
@@ -635,9 +613,6 @@ async def test_eth_send_transaction_no_max_fee(
         assert txn["value"] == 1
         assert txn["gas"] == 21000
 
-        block = await async_w3.eth.get_block("latest")
-        assert txn["maxFeePerGas"] == maxPriorityFeePerGas + 2 * block["baseFeePerGas"]
-
     @pytest.mark.asyncio
     async def test_eth_send_transaction_max_fee_less_than_tip(
         self,
@@ -741,6 +716,86 @@ async def test_async_sign_and_send_raw_middleware(
         # clean up
         async_w3.middleware_onion.remove("signing")
 
+    @pytest.mark.asyncio
+    async def test_async_sign_authorization_and_send_raw_set_code_transaction(
+        self,
+        async_w3: "AsyncWeb3",
+        keyfile_account_pkey: HexStr,
+        async_math_contract: "AsyncContract",
+    ) -> None:
+        keyfile_account = async_w3.eth.account.from_key(keyfile_account_pkey)
+
+        chain_id = await async_w3.eth.chain_id
+        nonce = await async_w3.eth.get_transaction_count(keyfile_account.address)
+
+        auth = {
+            "chainId": chain_id,
+            "address": async_math_contract.address,
+            "nonce": nonce + 1,
+        }
+        signed_auth = keyfile_account.sign_authorization(auth)
+
+        # get current math counter and increase it only in the delegation by n
+        math_counter = await async_math_contract.functions.counter().call()
+        built_tx = await async_math_contract.functions.incrementCounter(
+            math_counter + 1337
+        ).build_transaction({})
+        txn: TxParams = {
+            "chainId": chain_id,
+            "to": keyfile_account.address,
+            "value": Wei(0),
+            "gas": 200_000,
+            "nonce": nonce,
+            "maxPriorityFeePerGas": Wei(10**9),
+            "maxFeePerGas": Wei(10**9),
+            "data": built_tx["data"],
+            "authorizationList": [signed_auth],
+        }
+
+        signed = keyfile_account.sign_transaction(txn)
+        tx_hash = await async_w3.eth.send_raw_transaction(signed.raw_transaction)
+        get_tx = await async_w3.eth.get_transaction(tx_hash)
+        await async_w3.eth.wait_for_transaction_receipt(tx_hash, timeout=10)
+
+        code = await async_w3.eth.get_code(keyfile_account.address)
+        assert code.to_0x_hex() == f"0xef0100{async_math_contract.address[2:].lower()}"
+        delegated = async_w3.eth.contract(
+            address=keyfile_account.address, abi=async_math_contract.abi
+        )
+        # assert the math counter is increased by 1337 only in delegated acct
+        assert await async_math_contract.functions.counter().call() == math_counter
+        delegated_call = await delegated.functions.counter().call()
+        assert delegated_call == math_counter + 1337
+
+        assert len(get_tx["authorizationList"]) == 1
+        get_auth = get_tx["authorizationList"][0]
+        assert get_auth["chainId"] == chain_id
+        assert get_auth["address"] == async_math_contract.address
+        assert get_auth["nonce"] == nonce + 1
+        assert isinstance(get_auth["yParity"], int)
+        assert isinstance(get_auth["r"], HexBytes)
+        assert isinstance(get_auth["s"], HexBytes)
+
+        # reset code
+        reset_auth = {
+            "chainId": chain_id,
+            "address": "0x" + ("00" * 20),
+            "nonce": nonce + 3,
+        }
+        signed_reset_auth = keyfile_account.sign_authorization(reset_auth)
+        new_txn = dict(txn)
+        new_txn["authorizationList"] = [signed_reset_auth]
+        new_txn["nonce"] = nonce + 2
+
+        signed_reset = keyfile_account.sign_transaction(new_txn)
+        reset_tx_hash = await async_w3.eth.send_raw_transaction(
+            signed_reset.raw_transaction
+        )
+        await async_w3.eth.wait_for_transaction_receipt(reset_tx_hash, timeout=10)
+
+        reset_code = await async_w3.eth.get_code(keyfile_account.address)
+        assert reset_code == HexBytes("0x")
+
     @pytest.mark.asyncio
     async def test_GasPriceStrategyMiddleware(
         self,
@@ -1760,7 +1815,6 @@ async def test_async_eth_get_transaction_receipt_mined(
         assert isinstance(effective_gas_price, int)
         assert effective_gas_price > 0
 
-    @flaky_geth_dev_mining
     @pytest.mark.asyncio
     async def test_async_eth_get_transaction_receipt_unmined(
         self,
@@ -1826,7 +1880,6 @@ async def test_async_eth_wait_for_transaction_receipt_mined(
         assert isinstance(effective_gas_price, int)
         assert effective_gas_price > 0
 
-    @flaky_geth_dev_mining
     @pytest.mark.asyncio
     async def test_async_eth_wait_for_transaction_receipt_unmined(
         self,
@@ -2248,7 +2301,6 @@ async def test_async_eth_sign_ens_names(
             assert is_bytes(signature)
             assert len(signature) == 32 + 32 + 1
 
-    @flaky_geth_dev_mining
     @pytest.mark.asyncio
     async def test_async_eth_replace_transaction_legacy(
         self,
@@ -2278,7 +2330,6 @@ async def test_async_eth_replace_transaction_legacy(
         assert replace_txn["gas"] == 21000
         assert replace_txn["gasPrice"] == txn_params["gasPrice"]
 
-    @flaky_geth_dev_mining
     @pytest.mark.asyncio
     async def test_async_eth_replace_transaction(
         self,
@@ -2315,7 +2366,6 @@ async def test_async_eth_replace_transaction(
         assert replace_txn["maxFeePerGas"] == three_gwei_in_wei
         assert replace_txn["maxPriorityFeePerGas"] == two_gwei_in_wei
 
-    @flaky_geth_dev_mining
     @pytest.mark.asyncio
     async def test_async_eth_replace_transaction_underpriced(
         self,
@@ -2342,7 +2392,6 @@ async def test_async_eth_replace_transaction_underpriced(
         with pytest.raises(Web3RPCError, match="replacement transaction underpriced"):
             await async_w3.eth.replace_transaction(txn_hash, txn_params)
 
-    @flaky_geth_dev_mining
     @pytest.mark.asyncio
     async def test_async_eth_replace_transaction_non_existing_transaction(
         self,
@@ -2365,7 +2414,6 @@ async def test_async_eth_replace_transaction_non_existing_transaction(
                 txn_params,
             )
 
-    @flaky_geth_dev_mining
     @pytest.mark.asyncio
     async def test_async_eth_replace_transaction_already_mined(
         self,
@@ -2388,7 +2436,6 @@ async def test_async_eth_replace_transaction_already_mined(
         with pytest.raises(Web3ValueError, match="Supplied transaction with hash"):
             await async_w3.eth.replace_transaction(txn_hash, txn_params)
 
-    @flaky_geth_dev_mining
     @pytest.mark.asyncio
     async def test_async_eth_replace_transaction_incorrect_nonce(
         self, async_w3: "AsyncWeb3", async_keyfile_account_address: ChecksumAddress
@@ -2410,7 +2457,6 @@ async def test_async_eth_replace_transaction_incorrect_nonce(
         with pytest.raises(Web3ValueError):
             await async_w3.eth.replace_transaction(txn_hash, txn_params)
 
-    @flaky_geth_dev_mining
     @pytest.mark.asyncio
     async def test_async_eth_replace_transaction_gas_price_too_low(
         self,
@@ -2430,7 +2476,6 @@ async def test_async_eth_replace_transaction_gas_price_too_low(
         with pytest.raises(Web3ValueError):
             await async_w3.eth.replace_transaction(txn_hash, txn_params)
 
-    @flaky_geth_dev_mining
     @pytest.mark.asyncio
     async def test_async_eth_replace_transaction_gas_price_defaulting_minimum(
         self, async_w3: "AsyncWeb3", async_keyfile_account_address: ChecksumAddress
@@ -2454,7 +2499,6 @@ async def test_async_eth_replace_transaction_gas_price_defaulting_minimum(
             gas_price * 1.125
         )  # minimum gas price
 
-    @flaky_geth_dev_mining
     @pytest.mark.asyncio
     async def test_async_eth_replace_transaction_gas_price_defaulting_strategy_higher(
         self, async_w3: "AsyncWeb3", async_keyfile_account_address: ChecksumAddress
@@ -2483,7 +2527,6 @@ def higher_gas_price_strategy(_async_w3: "AsyncWeb3", _txn: TxParams) -> Wei:
         )  # Strategy provides higher gas price
         async_w3.eth.set_gas_price_strategy(None)  # reset strategy
 
-    @flaky_geth_dev_mining
     @pytest.mark.asyncio
     async def test_async_eth_replace_transaction_gas_price_defaulting_strategy_lower(
         self, async_w3: "AsyncWeb3", async_keyfile_account_address: ChecksumAddress
@@ -3457,7 +3500,6 @@ def gas_price_strategy(_w3: "Web3", _txn: TxParams) -> str:
         assert txn["gasPrice"] == two_gwei_in_wei
         w3.eth.set_gas_price_strategy(None)  # reset strategy
 
-    @flaky_geth_dev_mining
     def test_eth_replace_transaction_legacy(
         self, w3: "Web3", keyfile_account_address_dual_type: ChecksumAddress
     ) -> None:
@@ -3486,7 +3528,6 @@ def test_eth_replace_transaction_legacy(
         assert replace_txn["gas"] == 21000
         assert replace_txn["gasPrice"] == txn_params["gasPrice"]
 
-    @flaky_geth_dev_mining
     def test_eth_replace_transaction(
         self, w3: "Web3", keyfile_account_address_dual_type: ChecksumAddress
     ) -> None:
@@ -3520,7 +3561,6 @@ def test_eth_replace_transaction(
         assert replace_txn["maxFeePerGas"] == three_gwei_in_wei
         assert replace_txn["maxPriorityFeePerGas"] == two_gwei_in_wei
 
-    @flaky_geth_dev_mining
     def test_eth_replace_transaction_underpriced(
         self, w3: "Web3", keyfile_account_address_dual_type: ChecksumAddress
     ) -> None:
@@ -3544,7 +3584,6 @@ def test_eth_replace_transaction_underpriced(
         with pytest.raises(Web3RPCError, match="replacement transaction underpriced"):
             w3.eth.replace_transaction(txn_hash, txn_params)
 
-    @flaky_geth_dev_mining
     def test_eth_replace_transaction_non_existing_transaction(
         self, w3: "Web3", keyfile_account_address_dual_type: ChecksumAddress
     ) -> None:
@@ -3564,7 +3603,6 @@ def test_eth_replace_transaction_non_existing_transaction(
                 txn_params,
             )
 
-    @flaky_geth_dev_mining
     def test_eth_replace_transaction_already_mined(
         self, w3: "Web3", keyfile_account_address_dual_type: ChecksumAddress
     ) -> None:
@@ -3584,7 +3622,6 @@ def test_eth_replace_transaction_already_mined(
         with pytest.raises(Web3ValueError, match="Supplied transaction with hash"):
             w3.eth.replace_transaction(txn_hash, txn_params)
 
-    @flaky_geth_dev_mining
     def test_eth_replace_transaction_incorrect_nonce(
         self, w3: "Web3", keyfile_account_address: ChecksumAddress
     ) -> None:
@@ -3605,7 +3642,6 @@ def test_eth_replace_transaction_incorrect_nonce(
         with pytest.raises(Web3ValueError):
             w3.eth.replace_transaction(txn_hash, txn_params)
 
-    @flaky_geth_dev_mining
     def test_eth_replace_transaction_gas_price_too_low(
         self, w3: "Web3", keyfile_account_address_dual_type: ChecksumAddress
     ) -> None:
@@ -3622,7 +3658,6 @@ def test_eth_replace_transaction_gas_price_too_low(
         with pytest.raises(Web3ValueError):
             w3.eth.replace_transaction(txn_hash, txn_params)
 
-    @flaky_geth_dev_mining
     def test_eth_replace_transaction_gas_price_defaulting_minimum(
         self, w3: "Web3", keyfile_account_address: ChecksumAddress
     ) -> None:
@@ -3645,7 +3680,6 @@ def test_eth_replace_transaction_gas_price_defaulting_minimum(
             gas_price * 1.125
         )  # minimum gas price
 
-    @flaky_geth_dev_mining
     def test_eth_replace_transaction_gas_price_defaulting_strategy_higher(
         self, w3: "Web3", keyfile_account_address: ChecksumAddress
     ) -> None:
@@ -3673,7 +3707,6 @@ def higher_gas_price_strategy(w3: "Web3", txn: TxParams) -> Wei:
         )  # Strategy provides higher gas price
         w3.eth.set_gas_price_strategy(None)  # reset strategy
 
-    @flaky_geth_dev_mining
     def test_eth_replace_transaction_gas_price_defaulting_strategy_lower(
         self, w3: "Web3", keyfile_account_address: ChecksumAddress
     ) -> None:
@@ -3799,6 +3832,79 @@ def test_sign_and_send_raw_middleware(
         # cleanup
         w3.middleware_onion.remove("signing")
 
+    def test_sign_authorization_and_send_raw_set_code_transaction(
+        self, w3: "Web3", keyfile_account_pkey: HexStr, math_contract: "Contract"
+    ) -> None:
+        keyfile_account = w3.eth.account.from_key(keyfile_account_pkey)
+
+        chain_id = w3.eth.chain_id
+        nonce = w3.eth.get_transaction_count(keyfile_account.address)
+
+        auth = {
+            "chainId": chain_id,
+            "address": math_contract.address,
+            "nonce": nonce + 1,
+        }
+        signed_auth = keyfile_account.sign_authorization(auth)
+
+        # get current math counter and increase it only in the delegation by n
+        math_counter = math_contract.functions.counter().call()
+        data = math_contract.functions.incrementCounter(
+            math_counter + 1337
+        ).build_transaction({})["data"]
+        txn: TxParams = {
+            "chainId": chain_id,
+            "to": keyfile_account.address,
+            "value": Wei(0),
+            "gas": 200_000,
+            "nonce": nonce,
+            "maxPriorityFeePerGas": Wei(10**9),
+            "maxFeePerGas": Wei(10**9),
+            "data": data,
+            "authorizationList": [signed_auth],
+        }
+
+        signed = keyfile_account.sign_transaction(txn)
+        tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
+        get_tx = w3.eth.get_transaction(tx_hash)
+        w3.eth.wait_for_transaction_receipt(tx_hash, timeout=10)
+
+        code = w3.eth.get_code(keyfile_account.address)
+        assert code.to_0x_hex() == f"0xef0100{math_contract.address[2:].lower()}"
+        delegated = w3.eth.contract(
+            address=keyfile_account.address, abi=math_contract.abi
+        )
+        # assert the math counter is increased by 1337 only in delegated acct
+        assert math_contract.functions.counter().call() == math_counter
+        assert delegated.functions.counter().call() == math_counter + 1337
+
+        assert len(get_tx["authorizationList"]) == 1
+        get_auth = get_tx["authorizationList"][0]
+        assert get_auth["chainId"] == chain_id
+        assert get_auth["address"] == math_contract.address
+        assert get_auth["nonce"] == nonce + 1
+        assert isinstance(get_auth["yParity"], int)
+        assert isinstance(get_auth["r"], HexBytes)
+        assert isinstance(get_auth["s"], HexBytes)
+
+        # reset storage value and code
+        reset_auth = {
+            "chainId": chain_id,
+            "address": "0x" + ("00" * 20),
+            "nonce": nonce + 3,
+        }
+        signed_reset_auth = keyfile_account.sign_authorization(reset_auth)
+        new_txn = dict(txn)
+        new_txn["authorizationList"] = [signed_reset_auth]
+        new_txn["nonce"] = nonce + 2
+
+        signed_reset = keyfile_account.sign_transaction(new_txn)
+        reset_tx_hash = w3.eth.send_raw_transaction(signed_reset.raw_transaction)
+        w3.eth.wait_for_transaction_receipt(reset_tx_hash, timeout=10)
+
+        reset_code = w3.eth.get_code(keyfile_account.address)
+        assert reset_code == HexBytes("0x")
+
     def test_eth_call(self, w3: "Web3", math_contract: "Contract") -> None:
         txn_params = math_contract._prepare_transaction(
             abi_element_identifier="add",
@@ -4507,7 +4613,6 @@ def test_eth_get_transaction_receipt_mined(
         assert isinstance(effective_gas_price, int)
         assert effective_gas_price > 0
 
-    @flaky_geth_dev_mining
     def test_eth_get_transaction_receipt_unmined(
         self, w3: "Web3", keyfile_account_address_dual_type: ChecksumAddress
     ) -> None:
@@ -4565,7 +4670,6 @@ def test_eth_wait_for_transaction_receipt_mined(
         assert isinstance(effective_gas_price, int)
         assert effective_gas_price > 0
 
-    @flaky_geth_dev_mining
     def test_eth_wait_for_transaction_receipt_unmined(
         self, w3: "Web3", keyfile_account_address_dual_type: ChecksumAddress
     ) -> None:
diff --git a/web3/_utils/module_testing/module_testing_utils.py b/web3/_utils/module_testing/module_testing_utils.py
index 289b3386b1..f369d07804 100644
--- a/web3/_utils/module_testing/module_testing_utils.py
+++ b/web3/_utils/module_testing/module_testing_utils.py
@@ -21,9 +21,6 @@
 from eth_utils import (
     is_same_address,
 )
-from flaky import (
-    flaky,
-)
 from hexbytes import (
     HexBytes,
 )
@@ -44,20 +41,11 @@
     )
     from requests import Response  # noqa: F401
 
-    from web3 import Web3  # noqa: F401
     from web3._utils.compat import (  # noqa: F401
         Self,
     )
 
 
-"""
-flaky_geth_dev_mining decorator for tests requiring a pending block
-for the duration of the test. This behavior can be flaky
-due to timing of the test running as a block is mined.
-"""
-flaky_geth_dev_mining = flaky(max_runs=3, min_passes=1)
-
-
 def assert_contains_log(
     result: Sequence[LogReceipt],
     block_with_txn_with_log: BlockData,
diff --git a/web3/_utils/module_testing/persistent_connection_provider.py b/web3/_utils/module_testing/persistent_connection_provider.py
index bdbf30efd8..1eeae2f132 100644
--- a/web3/_utils/module_testing/persistent_connection_provider.py
+++ b/web3/_utils/module_testing/persistent_connection_provider.py
@@ -655,11 +655,11 @@ async def test_asyncio_gather_for_multiple_requests_matches_the_responses(
         assert all(k in pending.keys() for k in SOME_BLOCK_KEYS)
 
         assert isinstance(block_num, int)
-        assert latest["number"] == block_num
-
         assert isinstance(chain_id, int)
         assert isinstance(chain_id2, int)
         assert isinstance(chain_id3, int)
+        # chain id is set in fixture file
+        assert chain_id == chain_id2 == chain_id3 == 131277322940537
 
     @pytest.mark.asyncio
     async def test_async_public_socket_api(self, async_w3: AsyncWeb3) -> None:
@@ -854,7 +854,7 @@ async def test_handle_subscriptions_breaks_on_unsubscribe(
         async_w3: AsyncWeb3,
     ) -> None:
         async def unsubscribe_subs(
-            subs: List[Union[NewHeadsSubscription, LogsSubscription]]
+            subs: List[Union[NewHeadsSubscription, LogsSubscription]],
         ) -> None:
             for sub in subs:
                 await sub.unsubscribe()
diff --git a/web3/providers/eth_tester/middleware.py b/web3/providers/eth_tester/middleware.py
index 72ab204076..6a22a083b6 100644
--- a/web3/providers/eth_tester/middleware.py
+++ b/web3/providers/eth_tester/middleware.py
@@ -78,6 +78,7 @@ def is_hexstr(value: Any) -> bool:
     "maxFeePerGas": "max_fee_per_gas",
     "maxPriorityFeePerGas": "max_priority_fee_per_gas",
     "accessList": "access_list",
+    "authorizationList": "authorization_list",
     "chainId": "chain_id",
 }
 transaction_request_remapper = apply_key_map(TRANSACTION_REQUEST_KEY_MAPPING)
@@ -94,6 +95,20 @@ def is_hexstr(value: Any) -> bool:
     "accessList": apply_list_to_array_formatter(
         apply_key_map({"storageKeys": "storage_keys"})
     ),
+    "authorizationList": apply_list_to_array_formatter(
+        compose(
+            apply_formatters_to_dict(
+                {
+                    "chain_id": to_integer_if_hex,
+                    "nonce": to_integer_if_hex,
+                    "y_parity": to_integer_if_hex,
+                    "r": to_integer_if_hex,
+                    "s": to_integer_if_hex,
+                },
+            ),
+            apply_key_map({"chainId": "chain_id", "yParity": "y_parity"}),
+        )
+    ),
 }
 transaction_request_formatter = apply_formatters_to_dict(TRANSACTION_REQUEST_FORMATTERS)
 
@@ -125,6 +140,7 @@ def is_hexstr(value: Any) -> bool:
 
 TRANSACTION_RESULT_KEY_MAPPING = {
     "access_list": "accessList",
+    "authorization_list": "authorizationList",
     "blob_versioned_hashes": "blobVersionedHashes",
     "block_hash": "blockHash",
     "block_number": "blockNumber",
@@ -145,6 +161,9 @@ def is_hexstr(value: Any) -> bool:
     "access_list": apply_list_to_array_formatter(
         apply_key_map({"storage_keys": "storageKeys"}),
     ),
+    "authorization_list": apply_list_to_array_formatter(
+        apply_key_map({"chain_id": "chainId", "y_parity": "yParity"}),
+    ),
 }
 transaction_result_formatter = apply_formatters_to_dict(TRANSACTION_RESULT_FORMATTERS)
 
@@ -195,6 +214,7 @@ def is_hexstr(value: Any) -> bool:
     "parent_beacon_block_root": "parentBeaconBlockRoot",
     "blob_gas_used": "blobGasUsed",
     "excess_blob_gas": "excessBlobGas",
+    "requests_hash": "requestsHash",
 }
 block_result_remapper = apply_key_map(BLOCK_RESULT_KEY_MAPPING)
 
diff --git a/web3/types.py b/web3/types.py
index 240e859695..8a1f67ad44 100644
--- a/web3/types.py
+++ b/web3/types.py
@@ -16,6 +16,9 @@
     Union,
 )
 
+from eth_account.datastructures import (
+    SignedSetCodeAuthorization,
+)
 from eth_typing import (
     Address,
     BlockNumber,
@@ -94,11 +97,21 @@ class RPCError(TypedDict):
     data: NotRequired[str]
 
 
+class SetCodeAuthorizationData(TypedDict):
+    chainId: int
+    address: ChecksumAddress
+    nonce: Nonce
+    yParity: int
+    r: HexBytes
+    s: HexBytes
+
+
 # syntax b/c "from" keyword not allowed w/ class construction
 TxData = TypedDict(
     "TxData",
     {
         "accessList": AccessList,
+        "authorizationList": Sequence[SetCodeAuthorizationData],
         "blobVersionedHashes": Sequence[HexBytes],
         "blockHash": HexBytes,
         "blockNumber": BlockNumber,
@@ -125,11 +138,24 @@ class RPCError(TypedDict):
     total=False,
 )
 
+
+class SetCodeAuthorizationParams(TypedDict):
+    chainId: int
+    address: Union[Address, ChecksumAddress, str]
+    nonce: Nonce
+    y_parity: int
+    r: int
+    s: int
+
+
 # syntax b/c "from" keyword not allowed w/ class construction
 TxParams = TypedDict(
     "TxParams",
     {
         "accessList": AccessList,
+        "authorizationList": Sequence[
+            Union[SetCodeAuthorizationParams, SignedSetCodeAuthorization]
+        ],
         "blobVersionedHashes": Sequence[Union[str, HexStr, bytes, HexBytes]],
         "chainId": int,
         "data": Union[bytes, HexStr],
@@ -186,6 +212,7 @@ class BlockData(TypedDict, total=False):
     parentBeaconBlockRoot: HexBytes
     blobGasUsed: int
     excessBlobGas: int
+    requestsHash: HexBytes
 
     # ExtraDataToPOAMiddleware replaces extraData w/ proofOfAuthorityData
     proofOfAuthorityData: HexBytes


Reviews:
user: login: kclowes
body: :shipit: Nothing major stood out to me. For my own learning, is the fixture scope from `module` -> `function` for ease of parallelization, or is there another reason? It looks like test times are down with the parallelization you added, but could we get more speedup if we scope the fixtures wider?
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-28T18:18:38Z
user: login: fselmo
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-28T18:34:04Z
user: login: fselmo
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-28T18:34:46Z
user: login: fselmo
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-28T18:35:42Z
user: login: fselmo
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-28T18:35:53Z
user: login: fselmo
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-28T18:41:50Z
user: login: kclowes
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-28T18:44:32Z
user: login: kclowes
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-28T18:45:43Z
user: login: fselmo
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-28T18:55:19Z
user: login: fselmo
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-28T19:12:56Z
user: login: reedsa
body: 👍 
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-28T19:45:33Z
user: login: pacrob
body: :sheep:
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-28T19:51:24Z

Review comments:
diff_hunk: @@ -200,6 +201,16 @@ tests are written across different files within ``/web3/_utils/module_testing``.
   client-and-provider-specific test configurations exist. This is mostly used to
   override tests specific to the provider type for the respective client.
 
+The integration tests are each run in insolation to prevent muddied contexts. Because
+they are run in isolation, they can be parallelized with ``pytest-xdist`` in order to
+speed up the test suite. To run the tests in parallel, you can use the ``-n`` flag
+with ``pytest``. For example, to run the tests in parallel with 4 workers, you can
+use the following command:
+
+.. code:: sh
+
+    $ pytest tests/integration/go_ethereum/path/to/module/or/test -n 4
path: docs/contributing.rst
user: login: kclowes
body: maybe:
```suggestion
    $ pytest tests/integration/go_ethereum/path/to/module/or/test -n auto
```
created_at: 2025-04-28T17:49:46Z
author_association: COLLABORATOR
diff_hunk: @@ -20,17 +20,18 @@ allowlist_externals=make,pre-commit
 install_command=python -m pip install {opts} {packages}
 usedevelop=True
 commands=
+    # Note: `pytest-xdist` n=10 seems to cause connection issues with geth; keep it at 6 for now
     core: pytest {posargs:tests/core -m "not asyncio"}
     core_async: pytest {posargs:tests/core -m asyncio}
-    ens: pytest {posargs:tests/ens --ignore=tests/ens/normalization/test_normalize_name_ensip15.py}
-    ensip15: pytest {posargs:tests/ens/normalization/test_normalize_name_ensip15.py -q}
-    integration-goethereum-ipc: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ipc.py -k "not Async"}
-    integration-goethereum-ipc_async: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ipc.py -k Async}
-    integration-goethereum-http: pytest {posargs:tests/integration/go_ethereum/test_goethereum_http.py -k "not Async"}
-    integration-goethereum-http_async: pytest {posargs:tests/integration/go_ethereum/test_goethereum_http.py -k Async}
-    integration-goethereum-legacy_ws: pytest {posargs:tests/integration/go_ethereum/test_goethereum_legacy_ws.py}
-    integration-goethereum-ws: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ws}
-    integration-ethtester: pytest {posargs:tests/integration/test_ethereum_tester.py}
+    ens: pytest {posargs:tests/ens --ignore=tests/ens/normalization/test_normalize_name_ensip15.py -n 10}
+    ensip15: pytest {posargs:tests/ens/normalization/test_normalize_name_ensip15.py -q -n 10}
+    integration-goethereum-ipc: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ipc.py -k "not Async" -n 10}
+    integration-goethereum-ipc_async: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ipc.py -k Async -n 10}
+    integration-goethereum-http: pytest {posargs:tests/integration/go_ethereum/test_goethereum_http.py -k "not Async" -n 10}
+    integration-goethereum-http_async: pytest {posargs:tests/integration/go_ethereum/test_goethereum_http.py -k Async -n 10}
+    integration-goethereum-legacy_ws: pytest {posargs:tests/integration/go_ethereum/test_goethereum_legacy_ws.py -n 10}
+    integration-goethereum-ws: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ws -n 10}
+    integration-ethtester: pytest {posargs:tests/integration/test_ethereum_tester.py -n 10}
path: tox.ini
user: login: kclowes
body: I wonder if auto would be better here? then we're not hard coding a certain number. 
created_at: 2025-04-28T18:05:20Z
author_association: COLLABORATOR
diff_hunk: @@ -20,17 +20,18 @@ allowlist_externals=make,pre-commit
 install_command=python -m pip install {opts} {packages}
 usedevelop=True
 commands=
+    # Note: `pytest-xdist` n=10 seems to cause connection issues with geth; keep it at 6 for now
path: tox.ini
user: login: kclowes
body: I think this can go?
created_at: 2025-04-28T18:05:33Z
author_association: COLLABORATOR
diff_hunk: @@ -161,6 +164,12 @@ def type_aware_apply_formatters_to_dict(
     """
     Preserve ``AttributeDict`` types if original ``value`` was an ``AttributeDict``.
     """
+    # TODO: In v8, Use eth-utils 5.3.0 as lower pin where ``apply_formatters_to_dict``
path: web3/_utils/method_formatters.py
user: login: kclowes
body: Do we want to pull CamelModel into web3 in this PR?
created_at: 2025-04-28T18:06:08Z
author_association: COLLABORATOR
diff_hunk: @@ -3485,8 +3527,8 @@ def test_eth_replace_transaction_legacy(
         assert replace_txn["value"] == 1
         assert replace_txn["gas"] == 21000
         assert replace_txn["gasPrice"] == txn_params["gasPrice"]
+        print("yeeeeeeehhhboiiiiiiiii")
path: web3/_utils/module_testing/eth_module.py
user: login: kclowes
body: 😆 
created_at: 2025-04-28T18:09:15Z
author_association: COLLABORATOR
diff_hunk: @@ -3485,8 +3527,8 @@ def test_eth_replace_transaction_legacy(
         assert replace_txn["value"] == 1
         assert replace_txn["gas"] == 21000
         assert replace_txn["gasPrice"] == txn_params["gasPrice"]
+        print("yeeeeeeehhhboiiiiiiiii")
path: web3/_utils/module_testing/eth_module.py
user: login: fselmo
body: Can you tell how much joy this gave me? 😆 
created_at: 2025-04-28T18:34:04Z
author_association: COLLABORATOR
diff_hunk: @@ -161,6 +164,12 @@ def type_aware_apply_formatters_to_dict(
     """
     Preserve ``AttributeDict`` types if original ``value`` was an ``AttributeDict``.
     """
+    # TODO: In v8, Use eth-utils 5.3.0 as lower pin where ``apply_formatters_to_dict``
path: web3/_utils/method_formatters.py
user: login: fselmo
body: I suppose we can. Should I add it to this PR?
created_at: 2025-04-28T18:34:46Z
author_association: COLLABORATOR
diff_hunk: @@ -20,17 +20,18 @@ allowlist_externals=make,pre-commit
 install_command=python -m pip install {opts} {packages}
 usedevelop=True
 commands=
+    # Note: `pytest-xdist` n=10 seems to cause connection issues with geth; keep it at 6 for now
     core: pytest {posargs:tests/core -m "not asyncio"}
     core_async: pytest {posargs:tests/core -m asyncio}
-    ens: pytest {posargs:tests/ens --ignore=tests/ens/normalization/test_normalize_name_ensip15.py}
-    ensip15: pytest {posargs:tests/ens/normalization/test_normalize_name_ensip15.py -q}
-    integration-goethereum-ipc: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ipc.py -k "not Async"}
-    integration-goethereum-ipc_async: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ipc.py -k Async}
-    integration-goethereum-http: pytest {posargs:tests/integration/go_ethereum/test_goethereum_http.py -k "not Async"}
-    integration-goethereum-http_async: pytest {posargs:tests/integration/go_ethereum/test_goethereum_http.py -k Async}
-    integration-goethereum-legacy_ws: pytest {posargs:tests/integration/go_ethereum/test_goethereum_legacy_ws.py}
-    integration-goethereum-ws: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ws}
-    integration-ethtester: pytest {posargs:tests/integration/test_ethereum_tester.py}
+    ens: pytest {posargs:tests/ens --ignore=tests/ens/normalization/test_normalize_name_ensip15.py -n 10}
+    ensip15: pytest {posargs:tests/ens/normalization/test_normalize_name_ensip15.py -q -n 10}
+    integration-goethereum-ipc: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ipc.py -k "not Async" -n 10}
+    integration-goethereum-ipc_async: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ipc.py -k Async -n 10}
+    integration-goethereum-http: pytest {posargs:tests/integration/go_ethereum/test_goethereum_http.py -k "not Async" -n 10}
+    integration-goethereum-http_async: pytest {posargs:tests/integration/go_ethereum/test_goethereum_http.py -k Async -n 10}
+    integration-goethereum-legacy_ws: pytest {posargs:tests/integration/go_ethereum/test_goethereum_legacy_ws.py -n 10}
+    integration-goethereum-ws: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ws -n 10}
+    integration-ethtester: pytest {posargs:tests/integration/test_ethereum_tester.py -n 10}
path: tox.ini
user: login: fselmo
body: My only hesitation was that `auto` could end up being _more_ than `10`. I was sort of trying to set some lower limit. But I guess if it can handle more than `10` that would be ok?
created_at: 2025-04-28T18:35:42Z
author_association: COLLABORATOR
diff_hunk: @@ -20,17 +20,18 @@ allowlist_externals=make,pre-commit
 install_command=python -m pip install {opts} {packages}
 usedevelop=True
 commands=
+    # Note: `pytest-xdist` n=10 seems to cause connection issues with geth; keep it at 6 for now
     core: pytest {posargs:tests/core -m "not asyncio"}
     core_async: pytest {posargs:tests/core -m asyncio}
-    ens: pytest {posargs:tests/ens --ignore=tests/ens/normalization/test_normalize_name_ensip15.py}
-    ensip15: pytest {posargs:tests/ens/normalization/test_normalize_name_ensip15.py -q}
-    integration-goethereum-ipc: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ipc.py -k "not Async"}
-    integration-goethereum-ipc_async: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ipc.py -k Async}
-    integration-goethereum-http: pytest {posargs:tests/integration/go_ethereum/test_goethereum_http.py -k "not Async"}
-    integration-goethereum-http_async: pytest {posargs:tests/integration/go_ethereum/test_goethereum_http.py -k Async}
-    integration-goethereum-legacy_ws: pytest {posargs:tests/integration/go_ethereum/test_goethereum_legacy_ws.py}
-    integration-goethereum-ws: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ws}
-    integration-ethtester: pytest {posargs:tests/integration/test_ethereum_tester.py}
+    ens: pytest {posargs:tests/ens --ignore=tests/ens/normalization/test_normalize_name_ensip15.py -n 10}
+    ensip15: pytest {posargs:tests/ens/normalization/test_normalize_name_ensip15.py -q -n 10}
+    integration-goethereum-ipc: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ipc.py -k "not Async" -n 10}
+    integration-goethereum-ipc_async: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ipc.py -k Async -n 10}
+    integration-goethereum-http: pytest {posargs:tests/integration/go_ethereum/test_goethereum_http.py -k "not Async" -n 10}
+    integration-goethereum-http_async: pytest {posargs:tests/integration/go_ethereum/test_goethereum_http.py -k Async -n 10}
+    integration-goethereum-legacy_ws: pytest {posargs:tests/integration/go_ethereum/test_goethereum_legacy_ws.py -n 10}
+    integration-goethereum-ws: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ws -n 10}
+    integration-ethtester: pytest {posargs:tests/integration/test_ethereum_tester.py -n 10}
path: tox.ini
user: login: fselmo
body: Thoughts on that?
created_at: 2025-04-28T18:35:53Z
author_association: COLLABORATOR
diff_hunk: @@ -20,17 +20,18 @@ allowlist_externals=make,pre-commit
 install_command=python -m pip install {opts} {packages}
 usedevelop=True
 commands=
+    # Note: `pytest-xdist` n=10 seems to cause connection issues with geth; keep it at 6 for now
     core: pytest {posargs:tests/core -m "not asyncio"}
     core_async: pytest {posargs:tests/core -m asyncio}
-    ens: pytest {posargs:tests/ens --ignore=tests/ens/normalization/test_normalize_name_ensip15.py}
-    ensip15: pytest {posargs:tests/ens/normalization/test_normalize_name_ensip15.py -q}
-    integration-goethereum-ipc: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ipc.py -k "not Async"}
-    integration-goethereum-ipc_async: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ipc.py -k Async}
-    integration-goethereum-http: pytest {posargs:tests/integration/go_ethereum/test_goethereum_http.py -k "not Async"}
-    integration-goethereum-http_async: pytest {posargs:tests/integration/go_ethereum/test_goethereum_http.py -k Async}
-    integration-goethereum-legacy_ws: pytest {posargs:tests/integration/go_ethereum/test_goethereum_legacy_ws.py}
-    integration-goethereum-ws: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ws}
-    integration-ethtester: pytest {posargs:tests/integration/test_ethereum_tester.py}
+    ens: pytest {posargs:tests/ens --ignore=tests/ens/normalization/test_normalize_name_ensip15.py -n 10}
+    ensip15: pytest {posargs:tests/ens/normalization/test_normalize_name_ensip15.py -q -n 10}
+    integration-goethereum-ipc: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ipc.py -k "not Async" -n 10}
+    integration-goethereum-ipc_async: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ipc.py -k Async -n 10}
+    integration-goethereum-http: pytest {posargs:tests/integration/go_ethereum/test_goethereum_http.py -k "not Async" -n 10}
+    integration-goethereum-http_async: pytest {posargs:tests/integration/go_ethereum/test_goethereum_http.py -k Async -n 10}
+    integration-goethereum-legacy_ws: pytest {posargs:tests/integration/go_ethereum/test_goethereum_legacy_ws.py -n 10}
+    integration-goethereum-ws: pytest {posargs:tests/integration/go_ethereum/test_goethereum_ws -n 10}
+    integration-ethtester: pytest {posargs:tests/integration/test_ethereum_tester.py -n 10}
path: tox.ini
user: login: fselmo
body: I added it, let's see what auto does for the `xlarge` CI runs
created_at: 2025-04-28T18:41:50Z
author_association: COLLABORATOR
diff_hunk: @@ -161,6 +164,12 @@ def type_aware_apply_formatters_to_dict(
     """
     Preserve ``AttributeDict`` types if original ``value`` was an ``AttributeDict``.
     """
+    # TODO: In v8, Use eth-utils 5.3.0 as lower pin where ``apply_formatters_to_dict``
path: web3/_utils/method_formatters.py
user: login: kclowes
body: I'll leave that up to you!
created_at: 2025-04-28T18:44:32Z
author_association: COLLABORATOR
diff_hunk: @@ -3485,8 +3527,8 @@ def test_eth_replace_transaction_legacy(
         assert replace_txn["value"] == 1
         assert replace_txn["gas"] == 21000
         assert replace_txn["gasPrice"] == txn_params["gasPrice"]
+        print("yeeeeeeehhhboiiiiiiiii")
path: web3/_utils/module_testing/eth_module.py
user: login: kclowes
body: lol yes I can! 
created_at: 2025-04-28T18:45:43Z
author_association: COLLABORATOR
diff_hunk: @@ -161,6 +164,12 @@ def type_aware_apply_formatters_to_dict(
     """
     Preserve ``AttributeDict`` types if original ``value`` was an ``AttributeDict``.
     """
+    # TODO: In v8, Use eth-utils 5.3.0 as lower pin where ``apply_formatters_to_dict``
path: web3/_utils/method_formatters.py
user: login: fselmo
body: I added it in here 👍🏼
created_at: 2025-04-28T18:55:19Z
author_association: COLLABORATOR
diff_hunk: @@ -161,6 +164,12 @@ def type_aware_apply_formatters_to_dict(
     """
     Preserve ``AttributeDict`` types if original ``value`` was an ``AttributeDict``.
     """
+    # TODO: In v8, Use eth-utils 5.3.0 as lower pin where ``apply_formatters_to_dict``
path: web3/_utils/method_formatters.py
user: login: fselmo
body: Oh we can't. `eth-account` can't inherit from ``CamelModel`` so we can't support it here yet since ``SignedSetCodeAuthorization`` is coming from eth-account.

Putting it back.
created_at: 2025-04-28T19:12:56Z
author_association: COLLABORATOR

PR comments:
user: login: fselmo
created_at: 2025-04-26T03:23:00Z
body: I fixed the integration test issues 🙂  I think they are better this way... every test runs in its own context now and we can parallelize them with xdist in the CI which doesn't seem to cause any issues on the `xlarge` setup with `-n 10`.

This is ready for a review 👀 
author_association: COLLABORATOR
user: login: fselmo
created_at: 2025-04-28T18:44:49Z
body: > For my own learning, is the fixture scope from `module` -> `function` for ease of parallelization, or is there another reason? 

I think there are maybe a few fixtures we can change back to `module` but this is so that each test has its own instance of geth. This is the change that makes them run in isolation as each function is a single test.

---
edit: Even still, the overhead of _not_ changing only one or two fixtures to `module` or `session` is probably pretty low
author_association: COLLABORATOR
user: login: fselmo
created_at: 2025-04-28T19:35:59Z
body: @kclowes all changes from your comments accounted for. I don't think the ``dev.period`` is going to affect test times other than the ones that get a / wait for a transaction receipt, which should be 1 or 2 tests. Aside from those, tests should finish as soon as the test logic passes the test, which for most tests doesn't require block processing. I raised the ``dev.period`` to ``4`` in this PR since ``-n auto`` increased the number of workers to ~ ``36`` and slowed down processing time for each test, which ended up causing some issues due to mining.

In the end ``-n auto`` with increased ``dev.period`` seems like the right way to go. So far, running the CI with ``--dev.period=4`` seems to be plenty of time for the pending / replace transaction tests to run their logic before the block is processed.

I'm going to re-run the CI a few more times and make sure the success rate good and then I'll merge this.
author_association: COLLABORATOR