Skip to content

Commit eead3d6

Browse files
pacrobpacrob
authored and
pacrob
committed
async more filter tests (#2732)
* async existing filter test * async test_filter_against_transaction_logs * async test_filter_against_pending_transactions * async test_contract_get_logs * async test_contract_topic_filters * async test_contract_past_event_filtering * async test_contract_on_event_filtering * async test_contract_data_filters
1 parent e1abe7e commit eead3d6

15 files changed

+1062
-209
lines changed

newsfragments/2744.feature.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added async functionality to filter

tests/core/filtering/conftest.py

+12-4
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ def emitter_log_topics():
149149
return LogTopics
150150

151151

152-
def return_filter(contract=None, args=[]):
152+
def return_filter(contract, args):
153153
event_name = args[0]
154154
kwargs = apply_key_map({"filter": "argument_filters"}, args[1])
155155
if "fromBlock" not in kwargs:
@@ -196,6 +196,14 @@ async def async_emitter(
196196
)
197197

198198

199-
@pytest.fixture(scope="module")
200-
def async_create_filter(request):
201-
return async_partial(return_filter)
199+
async def async_return_filter(contract, args):
200+
event_name = args[0]
201+
kwargs = apply_key_map({"filter": "argument_filters"}, args[1])
202+
if "fromBlock" not in kwargs:
203+
kwargs["fromBlock"] = "latest"
204+
return await contract.events[event_name].create_filter(**kwargs)
205+
206+
207+
@pytest_asyncio.fixture(scope="module")
208+
async def async_create_filter(request):
209+
return async_partial(async_return_filter)

tests/core/filtering/test_basic_filter_tests.py

+3-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
import pytest
22

3-
from tests.core.filtering.utils import (
4-
async_range,
5-
)
6-
73

84
def test_filtering_sequential_blocks_with_bounded_range(
95
w3, emitter, Emitter, wait_for_transaction
@@ -51,7 +47,7 @@ async def test_async_filtering_sequential_blocks_with_bounded_range(
5147
initial_block_number = await async_w3.eth.block_number
5248
builder.toBlock = initial_block_number + 100
5349
filter_ = await builder.deploy(async_w3)
54-
async for i in async_range(100):
50+
for i in range(100):
5551
await async_emitter.functions.logNoArgs(which=1).transact()
5652
eth_block_number = await async_w3.eth.block_number
5753
assert eth_block_number == initial_block_number + 100
@@ -61,12 +57,12 @@ async def test_async_filtering_sequential_blocks_with_bounded_range(
6157

6258
@pytest.mark.asyncio
6359
async def test_async_filtering_starting_block_range(async_w3, async_emitter):
64-
async for i in async_range(10):
60+
for i in range(10):
6561
await async_emitter.functions.logNoArgs(which=1).transact()
6662
builder = async_emitter.events.LogNoArguments.build_filter()
6763
filter_ = await builder.deploy(async_w3)
6864
initial_block_number = await async_w3.eth.block_number
69-
async for i in async_range(10):
65+
for i in range(10):
7066
await async_emitter.functions.logNoArgs(which=1).transact()
7167
eth_block_number = await async_w3.eth.block_number
7268
assert eth_block_number == initial_block_number + 10

tests/core/filtering/test_contract_data_filters.py

+252-40
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,28 @@
1+
import asyncio
12
import pytest
23

34
from hypothesis import (
45
given,
56
settings,
67
strategies as st,
78
)
9+
import pytest_asyncio
810

9-
from web3 import Web3
11+
from tests.core.filtering.utils import (
12+
_async_emitter_fixture_logic,
13+
_async_w3_fixture_logic,
14+
_emitter_fixture_logic,
15+
_w3_fixture_logic,
16+
)
17+
from tests.utils import (
18+
_async_wait_for_block_fixture_logic,
19+
_async_wait_for_transaction_fixture_logic,
20+
)
1021
from web3._utils.module_testing.emitter_contract import (
1122
CONTRACT_EMITTER_ABI,
1223
CONTRACT_EMITTER_CODE,
1324
CONTRACT_EMITTER_RUNTIME,
1425
)
15-
from web3.middleware import (
16-
local_filter_middleware,
17-
)
18-
from web3.providers.eth_tester import (
19-
EthereumTesterProvider,
20-
)
21-
22-
23-
@pytest.fixture(
24-
scope="module",
25-
params=[True, False],
26-
ids=["local_filter_middleware", "node_based_filter"],
27-
)
28-
def w3(request):
29-
use_filter_middleware = request.param
30-
provider = EthereumTesterProvider()
31-
w3 = Web3(provider)
32-
if use_filter_middleware:
33-
w3.middleware_onion.add(local_filter_middleware)
34-
return w3
3526

3627

3728
@pytest.fixture(scope="module")
@@ -58,25 +49,6 @@ def EMITTER(EMITTER_CODE, EMITTER_RUNTIME, EMITTER_ABI):
5849
}
5950

6051

61-
@pytest.fixture(scope="module")
62-
def Emitter(w3, EMITTER):
63-
return w3.eth.contract(**EMITTER)
64-
65-
66-
@pytest.fixture(scope="module")
67-
def emitter(w3, Emitter, wait_for_transaction, wait_for_block, address_conversion_func):
68-
wait_for_block(w3)
69-
deploy_txn_hash = Emitter.constructor().transact({"gas": 10000000})
70-
deploy_receipt = wait_for_transaction(w3, deploy_txn_hash)
71-
contract_address = address_conversion_func(deploy_receipt["contractAddress"])
72-
73-
bytecode = w3.eth.get_code(contract_address)
74-
assert bytecode == Emitter.bytecode_runtime
75-
_emitter = Emitter(address=contract_address)
76-
assert _emitter.address == contract_address
77-
return _emitter
78-
79-
8052
def not_empty_string(x):
8153
return x != ""
8254

@@ -130,6 +102,30 @@ def array_values(draw):
130102
return (matching, non_matching)
131103

132104

105+
# --- sync --- #
106+
107+
108+
@pytest.fixture(
109+
scope="module",
110+
params=[True, False],
111+
ids=["local_filter_middleware", "node_based_filter"],
112+
)
113+
def w3(request):
114+
return _w3_fixture_logic(request)
115+
116+
117+
@pytest.fixture(scope="module")
118+
def Emitter(w3, EMITTER):
119+
return w3.eth.contract(**EMITTER)
120+
121+
122+
@pytest.fixture(scope="module")
123+
def emitter(w3, Emitter, wait_for_transaction, wait_for_block, address_conversion_func):
124+
return _emitter_fixture_logic(
125+
w3, Emitter, wait_for_transaction, wait_for_block, address_conversion_func
126+
)
127+
128+
133129
@pytest.mark.parametrize("api_style", ("v4", "build_filter"))
134130
@given(vals=dynamic_values())
135131
@settings(max_examples=5, deadline=None)
@@ -284,3 +280,219 @@ def test_data_filters_with_list_arguments(
284280
else:
285281
with pytest.raises(TypeError):
286282
create_filter(emitter, ["LogListArgs", {"filter": {"arg1": matching}}])
283+
284+
285+
# --- async --- #
286+
287+
288+
@pytest_asyncio.fixture(scope="module")
289+
async def async_wait_for_block():
290+
return _async_wait_for_block_fixture_logic
291+
292+
293+
@pytest_asyncio.fixture(scope="module")
294+
async def async_wait_for_transaction():
295+
return _async_wait_for_transaction_fixture_logic
296+
297+
298+
@pytest.fixture(scope="module")
299+
def event_loop():
300+
policy = asyncio.get_event_loop_policy()
301+
loop = policy.new_event_loop()
302+
yield loop
303+
loop.close()
304+
305+
306+
@pytest.fixture(
307+
scope="module",
308+
params=[True, False],
309+
ids=["local_filter_middleware", "node_based_filter"],
310+
)
311+
def async_w3(request):
312+
return _async_w3_fixture_logic(request)
313+
314+
315+
@pytest.fixture(scope="module")
316+
def AsyncEmitter(async_w3, EMITTER):
317+
return async_w3.eth.contract(**EMITTER)
318+
319+
320+
@pytest_asyncio.fixture(scope="module")
321+
async def async_emitter(
322+
async_w3,
323+
AsyncEmitter,
324+
async_wait_for_transaction,
325+
async_wait_for_block,
326+
address_conversion_func,
327+
):
328+
return await _async_emitter_fixture_logic(
329+
async_w3,
330+
AsyncEmitter,
331+
async_wait_for_transaction,
332+
async_wait_for_block,
333+
address_conversion_func,
334+
)
335+
336+
337+
@pytest.mark.asyncio
338+
@pytest.mark.parametrize("api_style", ("v4", "build_filter"))
339+
@given(vals=dynamic_values())
340+
@settings(max_examples=5, deadline=None)
341+
async def test_async_data_filters_with_dynamic_arguments(
342+
async_w3,
343+
async_wait_for_transaction,
344+
async_create_filter,
345+
async_emitter,
346+
api_style,
347+
vals,
348+
):
349+
if api_style == "build_filter":
350+
filter_builder = async_emitter.events.LogDynamicArgs.build_filter()
351+
filter_builder.args["arg1"].match_single(vals["matching"])
352+
event_filter = await filter_builder.deploy(async_w3)
353+
else:
354+
event_filter = await async_create_filter(
355+
async_emitter, ["LogDynamicArgs", {"filter": {"arg1": vals["matching"]}}]
356+
)
357+
358+
txn_hashes = [
359+
await async_emitter.functions.logDynamicArgs(
360+
arg0=vals["matching"], arg1=vals["matching"]
361+
).transact(
362+
{"maxFeePerGas": 10**9, "maxPriorityFeePerGas": 10**9, "gas": 400000}
363+
),
364+
await async_emitter.functions.logDynamicArgs(
365+
arg0=vals["non_matching"][0], arg1=vals["non_matching"][0]
366+
).transact(
367+
{"maxFeePerGas": 10**9, "maxPriorityFeePerGas": 10**9, "gas": 400000}
368+
),
369+
]
370+
371+
for txn_hash in txn_hashes:
372+
await async_wait_for_transaction(async_w3, txn_hash)
373+
374+
log_entries = await event_filter.get_new_entries()
375+
assert len(log_entries) == 1
376+
assert log_entries[0]["transactionHash"] == txn_hashes[0]
377+
378+
379+
@pytest.mark.asyncio
380+
@pytest.mark.parametrize("api_style", ("v4", "build_filter"))
381+
@given(vals=fixed_values())
382+
@settings(max_examples=5, deadline=None)
383+
async def test_async_data_filters_with_fixed_arguments(
384+
async_w3,
385+
async_emitter,
386+
async_wait_for_transaction,
387+
async_create_filter,
388+
api_style,
389+
vals,
390+
):
391+
if api_style == "build_filter":
392+
filter_builder = async_emitter.events.LogQuadrupleArg.build_filter()
393+
filter_builder.args["arg0"].match_single(vals["matching"][0])
394+
filter_builder.args["arg1"].match_single(vals["matching"][1])
395+
filter_builder.args["arg2"].match_single(vals["matching"][2])
396+
filter_builder.args["arg3"].match_single(vals["matching"][3])
397+
event_filter = await filter_builder.deploy(async_w3)
398+
else:
399+
event_filter = await async_create_filter(
400+
async_emitter,
401+
[
402+
"LogQuadrupleArg",
403+
{
404+
"filter": {
405+
"arg0": vals["matching"][0],
406+
"arg1": vals["matching"][1],
407+
"arg2": vals["matching"][2],
408+
"arg3": vals["matching"][3],
409+
}
410+
},
411+
],
412+
)
413+
414+
txn_hashes = []
415+
txn_hashes.append(
416+
await async_emitter.functions.logQuadruple(
417+
which=5,
418+
arg0=vals["matching"][0],
419+
arg1=vals["matching"][1],
420+
arg2=vals["matching"][2],
421+
arg3=vals["matching"][3],
422+
).transact(
423+
{"maxFeePerGas": 10**9, "maxPriorityFeePerGas": 10**9, "gas": 100000}
424+
)
425+
)
426+
txn_hashes.append(
427+
await async_emitter.functions.logQuadruple(
428+
which=5,
429+
arg0=vals["non_matching"][0],
430+
arg1=vals["non_matching"][1],
431+
arg2=vals["non_matching"][2],
432+
arg3=vals["non_matching"][3],
433+
).transact(
434+
{"maxFeePerGas": 10**9, "maxPriorityFeePerGas": 10**9, "gas": 100000}
435+
)
436+
)
437+
438+
for txn_hash in txn_hashes:
439+
await async_wait_for_transaction(async_w3, txn_hash)
440+
441+
log_entries = await event_filter.get_new_entries()
442+
assert len(log_entries) == 1
443+
assert log_entries[0]["transactionHash"] == txn_hashes[0]
444+
445+
446+
@pytest.mark.asyncio
447+
@pytest.mark.parametrize("api_style", ("v4", "build_filter"))
448+
@given(vals=array_values())
449+
@settings(max_examples=5, deadline=None)
450+
async def test_async_data_filters_with_list_arguments(
451+
async_w3,
452+
async_emitter,
453+
async_wait_for_transaction,
454+
async_create_filter,
455+
api_style,
456+
vals,
457+
):
458+
matching, non_matching = vals
459+
460+
if api_style == "build_filter":
461+
filter_builder = async_emitter.events.LogListArgs.build_filter()
462+
filter_builder.args["arg1"].match_single(matching)
463+
event_filter = await filter_builder.deploy(async_w3)
464+
465+
txn_hashes = []
466+
txn_hashes.append(
467+
await async_emitter.functions.logListArgs(
468+
arg0=matching, arg1=matching
469+
).transact({"maxFeePerGas": 10**9, "maxPriorityFeePerGas": 10**9})
470+
)
471+
txn_hashes.append(
472+
await async_emitter.functions.logListArgs(
473+
arg0=non_matching, arg1=non_matching
474+
).transact({"maxFeePerGas": 10**9, "maxPriorityFeePerGas": 10**9})
475+
)
476+
txn_hashes.append(
477+
await async_emitter.functions.logListArgs(
478+
arg0=non_matching, arg1=matching
479+
).transact({"maxFeePerGas": 10**9, "maxPriorityFeePerGas": 10**9})
480+
)
481+
txn_hashes.append(
482+
await async_emitter.functions.logListArgs(
483+
arg0=matching, arg1=non_matching
484+
).transact({"maxFeePerGas": 10**9, "maxPriorityFeePerGas": 10**9})
485+
)
486+
487+
for txn_hash in txn_hashes:
488+
await async_wait_for_transaction(async_w3, txn_hash)
489+
490+
log_entries = await event_filter.get_new_entries()
491+
assert len(log_entries) == 2
492+
assert log_entries[0]["transactionHash"] == txn_hashes[0]
493+
assert log_entries[1]["transactionHash"] == txn_hashes[2]
494+
else:
495+
with pytest.raises(TypeError):
496+
await async_create_filter(
497+
async_emitter, ["LogListArgs", {"filter": {"arg1": matching}}]
498+
)

0 commit comments

Comments
 (0)