Skip to content

Commit 1d97bcd

Browse files
Aerilymreedsa
andauthored
fix: correctly combine address and contract address list in event filter param construction (#3618)
* fix: correctly combine address and contract address list in event filter param construction * fix: handle list like and non list like possibilities for address and contract address in event filter param construct * fix: deduplicate event filter params address when contract_address is the same * Add tests with updates to validate and build filter_params with address and/or contract_address params * Newsfragment for #3618 * Additional test coverage for invalid addresses and return string values for single item lists * Fix address as bytes --------- Co-authored-by: Stuart Reed <[email protected]>
1 parent ae7f5aa commit 1d97bcd

File tree

3 files changed

+297
-59
lines changed

3 files changed

+297
-59
lines changed

newsfragments/3618.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix contract event ``FilterParams`` to validate and normalize ``address`` parameters.

tests/core/utilities/test_construct_event_filter_params.py

Lines changed: 257 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,47 +3,67 @@
33
from web3._utils.filters import (
44
construct_event_filter_params,
55
)
6+
from web3.exceptions import (
7+
InvalidAddress,
8+
Web3ValueError,
9+
)
610

7-
EVENT_1_ABI = {
8-
"anonymous": False,
9-
"inputs": [
10-
{"indexed": False, "name": "arg0", "type": "uint256"},
11-
{"indexed": True, "name": "arg1", "type": "uint256"},
12-
],
13-
"name": "Event_1",
14-
"type": "event",
15-
}
11+
12+
def hex_and_pad(i):
13+
unpadded_hex_value = hex(i).rstrip("L")
14+
return "0x" + unpadded_hex_value[2:].zfill(64)
15+
16+
17+
@pytest.fixture
18+
def event_abi():
19+
return {
20+
"anonymous": False,
21+
"inputs": [
22+
{"indexed": False, "name": "arg0", "type": "uint256"},
23+
{"indexed": True, "name": "arg1", "type": "uint256"},
24+
],
25+
"name": "Event_1",
26+
"type": "event",
27+
}
1628

1729

1830
@pytest.mark.parametrize(
19-
"event_abi,fn_kwargs,expected",
31+
"fn_kwargs,expected",
2032
(
21-
(
22-
EVENT_1_ABI,
33+
pytest.param(
2334
{},
2435
{
2536
"topics": [
2637
"0xb470a829ed7792f06947f0ca3730a570cb378329ddcf09f2b4efabd6326f51f6"
2738
],
2839
},
40+
id="no-args",
2941
),
30-
(
31-
EVENT_1_ABI,
42+
pytest.param(
3243
{"topics": ["should-overwrite-topics"]},
3344
{"topics": ["should-overwrite-topics"]},
45+
id="overwrite-topics",
3446
),
35-
(
36-
EVENT_1_ABI,
47+
pytest.param(
48+
{"address": None},
49+
{
50+
"topics": [
51+
"0xb470a829ed7792f06947f0ca3730a570cb378329ddcf09f2b4efabd6326f51f6"
52+
],
53+
},
54+
id="no-address",
55+
),
56+
pytest.param(
3757
{"contract_address": "0xd3CdA913deB6f67967B99D67aCDFa1712C293601"},
3858
{
3959
"topics": [
4060
"0xb470a829ed7792f06947f0ca3730a570cb378329ddcf09f2b4efabd6326f51f6"
4161
],
4262
"address": "0xd3CdA913deB6f67967B99D67aCDFa1712C293601",
4363
},
64+
id="contract_address-string",
4465
),
45-
(
46-
EVENT_1_ABI,
66+
pytest.param(
4767
{
4868
"contract_address": "0xd3CdA913deB6f67967B99D67aCDFa1712C293601",
4969
"address": "0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413",
@@ -57,37 +77,243 @@
5777
"0xd3CdA913deB6f67967B99D67aCDFa1712C293601",
5878
],
5979
},
80+
id="address-with-contract_address",
6081
),
61-
(
62-
EVENT_1_ABI,
82+
pytest.param(
83+
{
84+
"contract_address": ["0xd3CdA913deB6f67967B99D67aCDFa1712C293601"],
85+
"address": ["0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413"],
86+
},
87+
{
88+
"topics": [
89+
"0xb470a829ed7792f06947f0ca3730a570cb378329ddcf09f2b4efabd6326f51f6"
90+
],
91+
"address": [
92+
"0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413",
93+
"0xd3CdA913deB6f67967B99D67aCDFa1712C293601",
94+
],
95+
},
96+
id="single-item-address-list-with-contract_address-list",
97+
),
98+
pytest.param(
6399
{"address": "0xd3CdA913deB6f67967B99D67aCDFa1712C293601"},
64100
{
65101
"topics": [
66102
"0xb470a829ed7792f06947f0ca3730a570cb378329ddcf09f2b4efabd6326f51f6"
67103
],
68104
"address": "0xd3CdA913deB6f67967B99D67aCDFa1712C293601",
69105
},
106+
id="address-string",
107+
),
108+
pytest.param(
109+
{"address": b"\xf2\xe2F\xbbv\xdf\x87l\xef\x8b8\xae\x84\x13\x0fOU\xde9["},
110+
{
111+
"topics": [
112+
"0xb470a829ed7792f06947f0ca3730a570cb378329ddcf09f2b4efabd6326f51f6"
113+
],
114+
"address": b"\xf2\xe2F\xbbv\xdf\x87l\xef\x8b8\xae\x84\x13\x0fOU\xde9[",
115+
},
116+
id="address-bytes",
117+
),
118+
pytest.param(
119+
{
120+
"contract_address": b"\xf2\xe2F\xbbv\xdf\x87l\xef\x8b8\xae\x84\x13\x0fOU\xde9[", # noqa: E501
121+
"address": [
122+
b"\xf2\xe2F\xbbv\xdf\x87l\xef\x8b8\xae\x84\x13\x0fOU\xde9[",
123+
b"\xf2\xe2F\xbbv\xdf\x87l\xef\x8b8\xae\x84\x13\x0fOU\xde9[",
124+
],
125+
},
126+
{
127+
"topics": [
128+
"0xb470a829ed7792f06947f0ca3730a570cb378329ddcf09f2b4efabd6326f51f6"
129+
],
130+
"address": b"\xf2\xe2F\xbbv\xdf\x87l\xef\x8b8\xae\x84\x13\x0fOU\xde9[",
131+
},
132+
id="address-bytes-list",
133+
),
134+
pytest.param(
135+
{"address": ["0xd3CdA913deB6f67967B99D67aCDFa1712C293601"]},
136+
{
137+
"topics": [
138+
"0xb470a829ed7792f06947f0ca3730a570cb378329ddcf09f2b4efabd6326f51f6"
139+
],
140+
"address": "0xd3CdA913deB6f67967B99D67aCDFa1712C293601",
141+
},
142+
id="address-list",
143+
),
144+
pytest.param(
145+
{
146+
"address": [
147+
"0xd3CdA913deB6f67967B99D67aCDFa1712C293601",
148+
"0x1234567890123456789012345678901234567890",
149+
]
150+
},
151+
{
152+
"topics": [
153+
"0xb470a829ed7792f06947f0ca3730a570cb378329ddcf09f2b4efabd6326f51f6"
154+
],
155+
"address": [
156+
"0xd3CdA913deB6f67967B99D67aCDFa1712C293601",
157+
"0x1234567890123456789012345678901234567890",
158+
],
159+
},
160+
id="multiple-address",
161+
),
162+
pytest.param(
163+
{
164+
"address": "0xd3CdA913deB6f67967B99D67aCDFa1712C293601",
165+
"contract_address": ["0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413"],
166+
},
167+
{
168+
"topics": [
169+
"0xb470a829ed7792f06947f0ca3730a570cb378329ddcf09f2b4efabd6326f51f6"
170+
],
171+
"address": [
172+
"0xd3CdA913deB6f67967B99D67aCDFa1712C293601",
173+
"0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413",
174+
],
175+
},
176+
id="one-address-with-multiple-contract_address",
177+
),
178+
pytest.param(
179+
{
180+
"address": [
181+
"0xd3CdA913deB6f67967B99D67aCDFa1712C293601",
182+
"0x1234567890123456789012345678901234567890",
183+
],
184+
"contract_address": "0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413",
185+
},
186+
{
187+
"topics": [
188+
"0xb470a829ed7792f06947f0ca3730a570cb378329ddcf09f2b4efabd6326f51f6"
189+
],
190+
"address": [
191+
"0xd3CdA913deB6f67967B99D67aCDFa1712C293601",
192+
"0x1234567890123456789012345678901234567890",
193+
"0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413",
194+
],
195+
},
196+
id="multiple-address-with-one-contract_address",
197+
),
198+
pytest.param(
199+
{
200+
"address": [
201+
"0xd3CdA913deB6f67967B99D67aCDFa1712C293601",
202+
"0x1234567890123456789012345678901234567890",
203+
],
204+
"contract_address": [
205+
"0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413",
206+
"0x1234567890123456789012345678901234567890",
207+
],
208+
},
209+
{
210+
"topics": [
211+
"0xb470a829ed7792f06947f0ca3730a570cb378329ddcf09f2b4efabd6326f51f6"
212+
],
213+
"address": [
214+
"0xd3CdA913deB6f67967B99D67aCDFa1712C293601",
215+
"0x1234567890123456789012345678901234567890",
216+
"0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413",
217+
],
218+
},
219+
id="multiple-address-with-multiple-contract_address",
220+
),
221+
pytest.param(
222+
{
223+
"contract_address": "0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413",
224+
"topics": [
225+
"0xb470a829ed7792f06947f0ca3730a570cb378329ddcf09f2b4efabd6326f51f6"
226+
],
227+
"from_block": "latest",
228+
"to_block": "latest",
229+
"address": [
230+
"0xd3CdA913deB6f67967B99D67aCDFa1712C293601",
231+
"0x1234567890123456789012345678901234567890",
232+
"0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413",
233+
],
234+
},
235+
{
236+
"topics": [
237+
"0xb470a829ed7792f06947f0ca3730a570cb378329ddcf09f2b4efabd6326f51f6"
238+
],
239+
"address": [
240+
"0xd3CdA913deB6f67967B99D67aCDFa1712C293601",
241+
"0x1234567890123456789012345678901234567890",
242+
"0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413",
243+
],
244+
"fromBlock": "latest",
245+
"toBlock": "latest",
246+
},
247+
id="all-arguments-with-address-list",
70248
),
71249
),
72250
)
73251
def test_construct_event_filter_params(w3, event_abi, fn_kwargs, expected):
74-
_, actual = construct_event_filter_params(event_abi, w3.codec, **fn_kwargs)
75-
assert actual == expected
252+
_, filter_params = construct_event_filter_params(event_abi, w3.codec, **fn_kwargs)
253+
# Ensure that the filter_params contains the expected keys
254+
assert (
255+
filter_params.keys() == expected.keys()
256+
), f"Keys don't match. Expected {set(expected.keys())}, got {set(filter_params.keys())}" # noqa: E501
257+
# Verify all values in filter_params match the expected values
258+
for key, value in expected.items():
259+
if isinstance(value, list) and isinstance(filter_params[key], list):
260+
assert sorted(filter_params[key]) == sorted(
261+
value
262+
), f"Expected {key}={value}, got {key}={filter_params.get(key)}"
263+
else:
264+
assert (
265+
filter_params[key] == value
266+
), f"Expected {key}={value}, got {key}={filter_params.get(key)}"
76267

77268

78-
def hex_and_pad(i):
79-
unpadded_hex_value = hex(i).rstrip("L")
80-
return "0x" + unpadded_hex_value[2:].zfill(64)
269+
@pytest.mark.parametrize(
270+
"fn_kwargs, expected_exception",
271+
[
272+
pytest.param(
273+
{
274+
"contract_address": "0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
275+
"topics": [
276+
"0xb470a829ed7792f06947f0ca3730a570cb378329ddcf09f2b4efabd6326f51f6"
277+
],
278+
"address": [
279+
"0xd3cda913deb6f67967b99d67acdfa1712c293601",
280+
"0x1234567890123456789012345678901234567890",
281+
"0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413",
282+
],
283+
"from_block": 1,
284+
"to_block": 2,
285+
},
286+
InvalidAddress,
287+
id="invalid-checksum-address",
288+
),
289+
pytest.param(
290+
{
291+
"contract_address": "0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
292+
},
293+
InvalidAddress,
294+
id="invalid-checksum-contract-address",
295+
),
296+
pytest.param(
297+
{"address": {"invalid": "0x1234567890123456789012345678901234567890"}},
298+
Web3ValueError,
299+
id="unsupported-type-exception",
300+
),
301+
],
302+
)
303+
def test_construct_event_filter_params_exceptions(
304+
w3, event_abi, fn_kwargs, expected_exception
305+
):
306+
with pytest.raises(expected_exception):
307+
construct_event_filter_params(event_abi, w3.codec, **fn_kwargs)
81308

82309

83310
@pytest.mark.parametrize(
84-
"event_abi,fn_kwargs,expected",
311+
"fn_kwargs,expected",
85312
(
86-
(EVENT_1_ABI, {}, [[]]),
87-
(EVENT_1_ABI, {"argument_filters": {"arg0": 1}}, [[hex_and_pad(1)]]),
88-
(EVENT_1_ABI, {"argument_filters": {"arg0": [1]}}, [[hex_and_pad(1)]]),
313+
({}, [[]]),
314+
({"argument_filters": {"arg0": 1}}, [[hex_and_pad(1)]]),
315+
({"argument_filters": {"arg0": [1]}}, [[hex_and_pad(1)]]),
89316
(
90-
EVENT_1_ABI,
91317
{"argument_filters": {"arg0": [1, 2]}},
92318
[
93319
[hex_and_pad(1)],
@@ -97,7 +323,7 @@ def hex_and_pad(i):
97323
),
98324
)
99325
def test_construct_event_filter_params_for_data_filters(
100-
event_abi, w3, fn_kwargs, expected
326+
w3, event_abi, fn_kwargs, expected
101327
):
102328
actual, _ = construct_event_filter_params(event_abi, w3.codec, **fn_kwargs)
103329
assert actual == expected

0 commit comments

Comments
 (0)