Skip to content

Commit

Permalink
async contract filter methods & start async filter testing (#2715)
Browse files Browse the repository at this point in the history
# async contract filter methods
* set up async filter testing fixtures 
* async a few filter tests
  • Loading branch information
pacrob authored and pacrob committed Dec 2, 2022
1 parent 73d1956 commit e1abe7e
Show file tree
Hide file tree
Showing 15 changed files with 629 additions and 171 deletions.
71 changes: 36 additions & 35 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import asyncio
import pytest
import pytest_asyncio
import time
import warnings

Expand All @@ -14,27 +15,11 @@
EthereumTesterProvider,
)


class PollDelayCounter:
def __init__(self, initial_delay=0, max_delay=1, initial_step=0.01):
self.initial_delay = initial_delay
self.initial_step = initial_step
self.max_delay = max_delay
self.current_delay = initial_delay

def __call__(self):
delay = self.current_delay

if self.current_delay == 0:
self.current_delay += self.initial_step
else:
self.current_delay *= 2
self.current_delay = min(self.current_delay, self.max_delay)

return delay

def reset(self):
self.current_delay = self.initial_delay
from tests.utils import (
PollDelayCounter,
_async_wait_for_block_fixture_logic,
_async_wait_for_transaction_fixture_logic,
)


@pytest.fixture()
Expand All @@ -46,25 +31,12 @@ def is_testrpc_provider(provider):
return isinstance(provider, EthereumTesterProvider)


def is_async_testrpc_provider(provider):
return isinstance(provider, AsyncEthereumTesterProvider)


@pytest.fixture()
def skip_if_testrpc():

def _skip_if_testrpc(w3):
if is_testrpc_provider(w3.provider):
pytest.skip()
return _skip_if_testrpc


@pytest.fixture()
def async_skip_if_testrpc():

def _skip_if_testrpc(async_w3):
if is_async_testrpc_provider(async_w3.provider):
pytest.skip()
return _skip_if_testrpc


Expand All @@ -76,6 +48,7 @@ def _wait_for_miner_start(w3, timeout=60):
while not w3.eth.mining or not w3.eth.hashrate:
time.sleep(poll_delay_counter())
timeout.check()

return _wait_for_miner_start


Expand All @@ -89,6 +62,7 @@ def _wait_for_block(w3, block_number=1, timeout=None):
while w3.eth.block_number < block_number:
w3.manager.request_blocking("evm_mine", [])
timeout.sleep(poll_delay_counter())

return _wait_for_block


Expand All @@ -105,6 +79,7 @@ def _wait_for_transaction(w3, txn_hash, timeout=120):
timeout.check()

return txn_receipt

return _wait_for_transaction


Expand All @@ -123,4 +98,30 @@ def w3_strict_abi():

@pytest.fixture(autouse=True)
def print_warnings():
warnings.simplefilter('always')
warnings.simplefilter("always")


# --- async --- #


def is_async_testrpc_provider(provider):
return isinstance(provider, AsyncEthereumTesterProvider)


@pytest.fixture()
def async_skip_if_testrpc():
def _skip_if_testrpc(async_w3):
if is_async_testrpc_provider(async_w3.provider):
pytest.skip()

return _skip_if_testrpc


@pytest_asyncio.fixture()
async def async_wait_for_block():
return _async_wait_for_block_fixture_logic


@pytest_asyncio.fixture()
async def async_wait_for_transaction():
return _async_wait_for_transaction_fixture_logic
6 changes: 4 additions & 2 deletions tests/core/contracts/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
)
import pytest_asyncio

from _utils import (
from tests.core.contracts.utils import (
async_deploy,
async_partial,
deploy,
)
from tests.utils import (
async_partial,
)
from web3._utils.module_testing.emitter_contract import (
CONTRACT_EMITTER_ABI,
CONTRACT_EMITTER_CODE,
Expand Down
2 changes: 1 addition & 1 deletion tests/core/contracts/test_contract_call_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
)
import pytest_asyncio

from _utils import (
from tests.core.contracts.utils import (
async_deploy,
deploy,
)
Expand Down
2 changes: 1 addition & 1 deletion tests/core/contracts/test_contract_caller_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import pytest_asyncio

from _utils import (
from tests.core.contracts.utils import (
async_deploy,
deploy,
)
Expand Down
12 changes: 0 additions & 12 deletions tests/core/contracts/_utils.py → tests/core/contracts/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import asyncio

from eth_utils.toolz import (
identity,
)
Expand Down Expand Up @@ -27,13 +25,3 @@ async def async_deploy(async_web3, Contract, apply_func=identity, args=None):
assert contract.address == address
assert len(await async_web3.eth.get_code(contract.address)) > 0
return contract


def async_partial(f, *args, **kwargs):
async def f2(*args2, **kwargs2):
result = f(*args, *args2, **kwargs, **kwargs2)
if asyncio.iscoroutinefunction(f):
result = await result
return result

return f2
81 changes: 53 additions & 28 deletions tests/core/filtering/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,22 @@
encode_hex,
event_signature_to_log_topic,
)
import pytest_asyncio

from web3 import Web3
from tests.core.filtering.utils import (
_async_emitter_fixture_logic,
_async_w3_fixture_logic,
_emitter_fixture_logic,
_w3_fixture_logic,
)
from tests.utils import (
async_partial,
)
from web3._utils.module_testing.emitter_contract import (
CONTRACT_EMITTER_ABI,
CONTRACT_EMITTER_CODE,
CONTRACT_EMITTER_RUNTIME,
)
from web3.middleware import (
local_filter_middleware,
)
from web3.providers.eth_tester import (
EthereumTesterProvider,
)


@pytest.fixture(
Expand All @@ -27,17 +30,7 @@
ids=["local_filter_middleware", "node_based_filter"],
)
def w3(request):
use_filter_middleware = request.param
provider = EthereumTesterProvider()
w3 = Web3(provider)
if use_filter_middleware:
w3.middleware_onion.add(local_filter_middleware)
return w3


@pytest.fixture(autouse=True)
def wait_for_mining_start(w3, wait_for_block):
wait_for_block(w3)
return _w3_fixture_logic(request)


@pytest.fixture()
Expand Down Expand Up @@ -71,16 +64,9 @@ def Emitter(w3, EMITTER):

@pytest.fixture()
def emitter(w3, Emitter, wait_for_transaction, wait_for_block, address_conversion_func):
wait_for_block(w3)
deploy_txn_hash = Emitter.constructor().transact({"gas": 10000000})
deploy_receipt = wait_for_transaction(w3, deploy_txn_hash)
contract_address = address_conversion_func(deploy_receipt["contractAddress"])

bytecode = w3.eth.get_code(contract_address)
assert bytecode == Emitter.bytecode_runtime
_emitter = Emitter(address=contract_address)
assert _emitter.address == contract_address
return _emitter
return _emitter_fixture_logic(
w3, Emitter, wait_for_transaction, wait_for_block, address_conversion_func
)


class LogFunctions:
Expand Down Expand Up @@ -174,3 +160,42 @@ def return_filter(contract=None, args=[]):
@pytest.fixture(scope="module")
def create_filter(request):
return functools.partial(return_filter)


# --- async --- #


@pytest.fixture(
scope="function",
params=[True, False],
ids=["async_local_filter_middleware", "node_based_filter"],
)
def async_w3(request):
return _async_w3_fixture_logic(request)


@pytest.fixture()
def AsyncEmitter(async_w3, EMITTER):
return async_w3.eth.contract(**EMITTER)


@pytest_asyncio.fixture()
async def async_emitter(
async_w3,
AsyncEmitter,
async_wait_for_transaction,
async_wait_for_block,
address_conversion_func,
):
return await _async_emitter_fixture_logic(
async_w3,
AsyncEmitter,
async_wait_for_transaction,
async_wait_for_block,
address_conversion_func,
)


@pytest.fixture(scope="module")
def async_create_filter(request):
return async_partial(return_filter)
50 changes: 50 additions & 0 deletions tests/core/filtering/test_basic_filter_tests.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
import pytest

from tests.core.filtering.utils import (
async_range,
)


def test_filtering_sequential_blocks_with_bounded_range(
w3, emitter, Emitter, wait_for_transaction
):
Expand Down Expand Up @@ -30,3 +37,46 @@ def test_requesting_results_with_no_new_blocks(w3, emitter):
builder = emitter.events.LogNoArguments.build_filter()
filter_ = builder.deploy(w3)
assert len(filter_.get_new_entries()) == 0


# --- async --- #


@pytest.mark.asyncio
async def test_async_filtering_sequential_blocks_with_bounded_range(
async_w3, async_emitter
):
builder = async_emitter.events.LogNoArguments.build_filter()
builder.fromBlock = "latest"
initial_block_number = await async_w3.eth.block_number
builder.toBlock = initial_block_number + 100
filter_ = await builder.deploy(async_w3)
async for i in async_range(100):
await async_emitter.functions.logNoArgs(which=1).transact()
eth_block_number = await async_w3.eth.block_number
assert eth_block_number == initial_block_number + 100
new_entries = await filter_.get_new_entries()
assert len(new_entries) == 100


@pytest.mark.asyncio
async def test_async_filtering_starting_block_range(async_w3, async_emitter):
async for i in async_range(10):
await async_emitter.functions.logNoArgs(which=1).transact()
builder = async_emitter.events.LogNoArguments.build_filter()
filter_ = await builder.deploy(async_w3)
initial_block_number = await async_w3.eth.block_number
async for i in async_range(10):
await async_emitter.functions.logNoArgs(which=1).transact()
eth_block_number = await async_w3.eth.block_number
assert eth_block_number == initial_block_number + 10
new_entries = await filter_.get_new_entries()
assert len(new_entries) == 10


@pytest.mark.asyncio
async def test_async_requesting_results_with_no_new_blocks(async_w3, async_emitter):
builder = async_emitter.events.LogNoArguments.build_filter()
filter_ = await builder.deploy(async_w3)
new_entries = await filter_.get_new_entries()
assert len(new_entries) == 0
Loading

0 comments on commit e1abe7e

Please sign in to comment.