Skip to content

Isolate integration tests #3

New issue

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

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

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions newsfragments/3659.feature.rst
Original file line number Diff line number Diff line change
@@ -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.
1 change: 1 addition & 0 deletions newsfragments/3659.internal.rst
Original file line number Diff line number Diff line change
@@ -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.
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
Expand Down Expand Up @@ -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",
Expand Down
9 changes: 0 additions & 9 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 --- #


Expand Down
5 changes: 5 additions & 0 deletions tests/core/eth-module/test_block_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -109,6 +110,9 @@ def test_get_block_formatters_with_pre_formatted_values(w3, request_mocker):
"parentBeaconBlockRoot": (
"0x6470e77f1b8a55a49a57b3f74c2a10a76185636d65122053752ea5e4bb4dac59"
),
"requestsHash": (
"0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
),
}

with request_mocker(
Expand Down Expand Up @@ -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"]),
}
101 changes: 101 additions & 0 deletions tests/core/eth-module/test_transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,24 @@
import collections
import itertools

from eth_account import (
Account,
)
from eth_utils import (
to_checksum_address,
to_int,
)
from hexbytes import (
HexBytes,
)
import pytest_asyncio

from tests.core.contracts.utils import (
async_deploy,
)
from web3._utils.contract_sources.contract_data.math_contract import (
MATH_CONTRACT_DATA,
)
from web3._utils.ens import (
ens_addresses,
)
Expand All @@ -29,6 +39,20 @@
RECEIPT_TIMEOUT = 0.2


@pytest.fixture
def async_math_contract_factory(async_w3):
return async_w3.eth.contract(**MATH_CONTRACT_DATA)


@pytest_asyncio.fixture
async def async_math_contract(
async_w3, async_math_contract_factory, address_conversion_func
):
return await async_deploy(
async_w3, async_math_contract_factory, address_conversion_func
)


def _tx_indexing_response_iterator():
while True:
yield {"error": {"message": "transaction indexing in progress"}}
Expand Down Expand Up @@ -420,3 +444,80 @@ async def test_async_send_raw_blob_transaction(async_w3):
assert transaction["blobVersionedHashes"][0] == HexBytes(
"0x0127c38bcad458d932e828b580b9ad97310be01407dfa0ed88118735980a3e9a"
)


@pytest.mark.asyncio
async def test_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

math_contract_address = (
f"0x{async_math_contract.address.hex()}"
if isinstance(async_math_contract.address, bytes)
else async_math_contract.address
)
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 = 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{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() == 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")
52 changes: 0 additions & 52 deletions tests/core/providers/test_legacy_websocket_provider.py
Original file line number Diff line number Diff line change
@@ -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,
)
Expand All @@ -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)
Expand All @@ -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}*"
Expand Down
12 changes: 6 additions & 6 deletions tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,47 +19,47 @@
)


@pytest.fixture(scope="module")
@pytest.fixture
def math_contract_factory(w3):
contract_factory = w3.eth.contract(
abi=MATH_CONTRACT_ABI, bytecode=MATH_CONTRACT_BYTECODE
)
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
)
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
)
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
)
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
)
return contract_factory


@pytest.fixture(scope="module")
@pytest.fixture
def event_loop():
loop = asyncio.get_event_loop_policy().new_event_loop()
yield loop
Expand Down
Loading