Skip to content

async more filter tests #2732

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

Merged
merged 11 commits into from
Dec 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions tests/core/filtering/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def emitter_log_topics():
return LogTopics


def return_filter(contract=None, args=[]):
def return_filter(contract, args):
event_name = args[0]
kwargs = apply_key_map({"filter": "argument_filters"}, args[1])
if "fromBlock" not in kwargs:
Expand Down Expand Up @@ -196,6 +196,14 @@ async def async_emitter(
)


@pytest.fixture(scope="module")
def async_create_filter(request):
return async_partial(return_filter)
async def async_return_filter(contract, args):
event_name = args[0]
kwargs = apply_key_map({"filter": "argument_filters"}, args[1])
if "fromBlock" not in kwargs:
kwargs["fromBlock"] = "latest"
return await contract.events[event_name].create_filter(**kwargs)


@pytest_asyncio.fixture(scope="module")
async def async_create_filter(request):
return async_partial(async_return_filter)
10 changes: 3 additions & 7 deletions tests/core/filtering/test_basic_filter_tests.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
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 @@ -51,7 +47,7 @@ async def test_async_filtering_sequential_blocks_with_bounded_range(
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):
for i in 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
Expand All @@ -61,12 +57,12 @@ async def test_async_filtering_sequential_blocks_with_bounded_range(

@pytest.mark.asyncio
async def test_async_filtering_starting_block_range(async_w3, async_emitter):
async for i in async_range(10):
for i in 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):
for i in 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
Expand Down
292 changes: 252 additions & 40 deletions tests/core/filtering/test_contract_data_filters.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,28 @@
import asyncio
import pytest

from hypothesis import (
given,
settings,
strategies as st,
)
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_wait_for_block_fixture_logic,
_async_wait_for_transaction_fixture_logic,
)
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(
scope="module",
params=[True, False],
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(scope="module")
Expand All @@ -58,25 +49,6 @@ def EMITTER(EMITTER_CODE, EMITTER_RUNTIME, EMITTER_ABI):
}


@pytest.fixture(scope="module")
def Emitter(w3, EMITTER):
return w3.eth.contract(**EMITTER)


@pytest.fixture(scope="module")
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


def not_empty_string(x):
return x != ""

Expand Down Expand Up @@ -130,6 +102,30 @@ def array_values(draw):
return (matching, non_matching)


# --- sync --- #


@pytest.fixture(
scope="module",
params=[True, False],
ids=["local_filter_middleware", "node_based_filter"],
)
def w3(request):
return _w3_fixture_logic(request)


@pytest.fixture(scope="module")
def Emitter(w3, EMITTER):
return w3.eth.contract(**EMITTER)


@pytest.fixture(scope="module")
def emitter(w3, Emitter, wait_for_transaction, wait_for_block, address_conversion_func):
return _emitter_fixture_logic(
w3, Emitter, wait_for_transaction, wait_for_block, address_conversion_func
)


@pytest.mark.parametrize("api_style", ("v4", "build_filter"))
@given(vals=dynamic_values())
@settings(max_examples=5, deadline=None)
Expand Down Expand Up @@ -284,3 +280,219 @@ def test_data_filters_with_list_arguments(
else:
with pytest.raises(TypeError):
create_filter(emitter, ["LogListArgs", {"filter": {"arg1": matching}}])


# --- async --- #


@pytest_asyncio.fixture(scope="module")
async def async_wait_for_block():
return _async_wait_for_block_fixture_logic


@pytest_asyncio.fixture(scope="module")
async def async_wait_for_transaction():
return _async_wait_for_transaction_fixture_logic


@pytest.fixture(scope="module")
def event_loop():
policy = asyncio.get_event_loop_policy()
loop = policy.new_event_loop()
yield loop
loop.close()


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


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


@pytest_asyncio.fixture(scope="module")
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.mark.asyncio
@pytest.mark.parametrize("api_style", ("v4", "build_filter"))
@given(vals=dynamic_values())
@settings(max_examples=5, deadline=None)
async def test_async_data_filters_with_dynamic_arguments(
async_w3,
async_wait_for_transaction,
async_create_filter,
async_emitter,
api_style,
vals,
):
if api_style == "build_filter":
filter_builder = async_emitter.events.LogDynamicArgs.build_filter()
filter_builder.args["arg1"].match_single(vals["matching"])
event_filter = await filter_builder.deploy(async_w3)
else:
event_filter = await async_create_filter(
async_emitter, ["LogDynamicArgs", {"filter": {"arg1": vals["matching"]}}]
)

txn_hashes = [
await async_emitter.functions.logDynamicArgs(
arg0=vals["matching"], arg1=vals["matching"]
).transact(
{"maxFeePerGas": 10**9, "maxPriorityFeePerGas": 10**9, "gas": 400000}
),
await async_emitter.functions.logDynamicArgs(
arg0=vals["non_matching"][0], arg1=vals["non_matching"][0]
).transact(
{"maxFeePerGas": 10**9, "maxPriorityFeePerGas": 10**9, "gas": 400000}
),
]

for txn_hash in txn_hashes:
await async_wait_for_transaction(async_w3, txn_hash)

log_entries = await event_filter.get_new_entries()
assert len(log_entries) == 1
assert log_entries[0]["transactionHash"] == txn_hashes[0]


@pytest.mark.asyncio
@pytest.mark.parametrize("api_style", ("v4", "build_filter"))
@given(vals=fixed_values())
@settings(max_examples=5, deadline=None)
async def test_async_data_filters_with_fixed_arguments(
async_w3,
async_emitter,
async_wait_for_transaction,
async_create_filter,
api_style,
vals,
):
if api_style == "build_filter":
filter_builder = async_emitter.events.LogQuadrupleArg.build_filter()
filter_builder.args["arg0"].match_single(vals["matching"][0])
filter_builder.args["arg1"].match_single(vals["matching"][1])
filter_builder.args["arg2"].match_single(vals["matching"][2])
filter_builder.args["arg3"].match_single(vals["matching"][3])
event_filter = await filter_builder.deploy(async_w3)
else:
event_filter = await async_create_filter(
async_emitter,
[
"LogQuadrupleArg",
{
"filter": {
"arg0": vals["matching"][0],
"arg1": vals["matching"][1],
"arg2": vals["matching"][2],
"arg3": vals["matching"][3],
}
},
],
)

txn_hashes = []
txn_hashes.append(
await async_emitter.functions.logQuadruple(
which=5,
arg0=vals["matching"][0],
arg1=vals["matching"][1],
arg2=vals["matching"][2],
arg3=vals["matching"][3],
).transact(
{"maxFeePerGas": 10**9, "maxPriorityFeePerGas": 10**9, "gas": 100000}
)
)
txn_hashes.append(
await async_emitter.functions.logQuadruple(
which=5,
arg0=vals["non_matching"][0],
arg1=vals["non_matching"][1],
arg2=vals["non_matching"][2],
arg3=vals["non_matching"][3],
).transact(
{"maxFeePerGas": 10**9, "maxPriorityFeePerGas": 10**9, "gas": 100000}
)
)

for txn_hash in txn_hashes:
await async_wait_for_transaction(async_w3, txn_hash)

log_entries = await event_filter.get_new_entries()
assert len(log_entries) == 1
assert log_entries[0]["transactionHash"] == txn_hashes[0]


@pytest.mark.asyncio
@pytest.mark.parametrize("api_style", ("v4", "build_filter"))
@given(vals=array_values())
@settings(max_examples=5, deadline=None)
async def test_async_data_filters_with_list_arguments(
async_w3,
async_emitter,
async_wait_for_transaction,
async_create_filter,
api_style,
vals,
):
matching, non_matching = vals

if api_style == "build_filter":
filter_builder = async_emitter.events.LogListArgs.build_filter()
filter_builder.args["arg1"].match_single(matching)
event_filter = await filter_builder.deploy(async_w3)

txn_hashes = []
txn_hashes.append(
await async_emitter.functions.logListArgs(
arg0=matching, arg1=matching
).transact({"maxFeePerGas": 10**9, "maxPriorityFeePerGas": 10**9})
)
txn_hashes.append(
await async_emitter.functions.logListArgs(
arg0=non_matching, arg1=non_matching
).transact({"maxFeePerGas": 10**9, "maxPriorityFeePerGas": 10**9})
)
txn_hashes.append(
await async_emitter.functions.logListArgs(
arg0=non_matching, arg1=matching
).transact({"maxFeePerGas": 10**9, "maxPriorityFeePerGas": 10**9})
)
txn_hashes.append(
await async_emitter.functions.logListArgs(
arg0=matching, arg1=non_matching
).transact({"maxFeePerGas": 10**9, "maxPriorityFeePerGas": 10**9})
)

for txn_hash in txn_hashes:
await async_wait_for_transaction(async_w3, txn_hash)

log_entries = await event_filter.get_new_entries()
assert len(log_entries) == 2
assert log_entries[0]["transactionHash"] == txn_hashes[0]
assert log_entries[1]["transactionHash"] == txn_hashes[2]
else:
with pytest.raises(TypeError):
await async_create_filter(
async_emitter, ["LogListArgs", {"filter": {"arg1": matching}}]
)
Loading