web3 7.0.0b2__py3-none-any.whl → 7.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ens/__init__.py +13 -2
- ens/_normalization.py +4 -4
- ens/async_ens.py +27 -15
- ens/base_ens.py +3 -1
- ens/contract_data.py +2 -2
- ens/ens.py +10 -7
- ens/exceptions.py +16 -29
- ens/specs/nf.json +1 -1
- ens/specs/normalization_spec.json +1 -1
- ens/utils.py +24 -32
- web3/__init__.py +23 -12
- web3/_utils/abi.py +157 -263
- web3/_utils/async_transactions.py +34 -20
- web3/_utils/batching.py +217 -0
- web3/_utils/blocks.py +6 -2
- web3/_utils/caching/__init__.py +12 -0
- web3/_utils/caching/caching_utils.py +433 -0
- web3/_utils/caching/request_caching_validation.py +287 -0
- web3/_utils/compat/__init__.py +2 -3
- web3/_utils/contract_sources/compile_contracts.py +1 -1
- web3/_utils/contract_sources/contract_data/ambiguous_function_contract.py +42 -0
- web3/_utils/contract_sources/contract_data/arrays_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/bytes_contracts.py +5 -5
- web3/_utils/contract_sources/contract_data/constructor_contracts.py +7 -7
- web3/_utils/contract_sources/contract_data/contract_caller_tester.py +3 -3
- web3/_utils/contract_sources/contract_data/emitter_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/event_contracts.py +50 -5
- web3/_utils/contract_sources/contract_data/extended_resolver.py +3 -3
- web3/_utils/contract_sources/contract_data/fallback_function_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/function_name_tester_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/math_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/offchain_lookup.py +3 -3
- web3/_utils/contract_sources/contract_data/offchain_resolver.py +3 -3
- web3/_utils/contract_sources/contract_data/panic_errors_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/payable_tester.py +3 -3
- web3/_utils/contract_sources/contract_data/receive_function_contracts.py +5 -5
- web3/_utils/contract_sources/contract_data/reflector_contracts.py +3 -3
- web3/_utils/contract_sources/contract_data/revert_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/simple_resolver.py +3 -3
- web3/_utils/contract_sources/contract_data/storage_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/string_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/tuple_contracts.py +5 -5
- web3/_utils/contracts.py +172 -220
- web3/_utils/datatypes.py +5 -1
- web3/_utils/decorators.py +6 -1
- web3/_utils/empty.py +1 -1
- web3/_utils/encoding.py +16 -12
- web3/_utils/error_formatters_utils.py +5 -3
- web3/_utils/events.py +78 -72
- web3/_utils/fee_utils.py +1 -3
- web3/_utils/filters.py +24 -22
- web3/_utils/formatters.py +2 -2
- web3/_utils/http.py +8 -2
- web3/_utils/http_session_manager.py +314 -0
- web3/_utils/math.py +14 -15
- web3/_utils/method_formatters.py +161 -34
- web3/_utils/module.py +2 -1
- web3/_utils/module_testing/__init__.py +3 -2
- web3/_utils/module_testing/eth_module.py +736 -583
- web3/_utils/module_testing/go_ethereum_debug_module.py +128 -0
- web3/_utils/module_testing/module_testing_utils.py +81 -24
- web3/_utils/module_testing/persistent_connection_provider.py +702 -220
- web3/_utils/module_testing/utils.py +114 -33
- web3/_utils/module_testing/web3_module.py +438 -17
- web3/_utils/normalizers.py +13 -11
- web3/_utils/rpc_abi.py +10 -22
- web3/_utils/threads.py +8 -7
- web3/_utils/transactions.py +32 -25
- web3/_utils/type_conversion.py +5 -1
- web3/_utils/validation.py +20 -17
- web3/beacon/__init__.py +5 -0
- web3/beacon/api_endpoints.py +3 -0
- web3/beacon/async_beacon.py +29 -6
- web3/beacon/beacon.py +24 -6
- web3/contract/__init__.py +7 -0
- web3/contract/async_contract.py +285 -82
- web3/contract/base_contract.py +556 -258
- web3/contract/contract.py +295 -84
- web3/contract/utils.py +251 -55
- web3/datastructures.py +49 -34
- web3/eth/__init__.py +7 -0
- web3/eth/async_eth.py +89 -69
- web3/eth/base_eth.py +7 -3
- web3/eth/eth.py +43 -66
- web3/exceptions.py +158 -83
- web3/gas_strategies/time_based.py +8 -6
- web3/geth.py +53 -184
- web3/main.py +77 -17
- web3/manager.py +362 -95
- web3/method.py +43 -15
- web3/middleware/__init__.py +17 -0
- web3/middleware/attrdict.py +12 -22
- web3/middleware/base.py +55 -2
- web3/middleware/filter.py +45 -23
- web3/middleware/formatting.py +6 -3
- web3/middleware/names.py +4 -1
- web3/middleware/signing.py +15 -6
- web3/middleware/stalecheck.py +2 -1
- web3/module.py +61 -25
- web3/providers/__init__.py +21 -0
- web3/providers/async_base.py +87 -32
- web3/providers/base.py +77 -32
- web3/providers/eth_tester/__init__.py +5 -0
- web3/providers/eth_tester/defaults.py +2 -55
- web3/providers/eth_tester/main.py +41 -15
- web3/providers/eth_tester/middleware.py +16 -17
- web3/providers/ipc.py +41 -17
- web3/providers/legacy_websocket.py +26 -1
- web3/providers/persistent/__init__.py +7 -0
- web3/providers/persistent/async_ipc.py +61 -121
- web3/providers/persistent/persistent.py +323 -16
- web3/providers/persistent/persistent_connection.py +54 -5
- web3/providers/persistent/request_processor.py +136 -56
- web3/providers/persistent/subscription_container.py +56 -0
- web3/providers/persistent/subscription_manager.py +233 -0
- web3/providers/persistent/websocket.py +29 -92
- web3/providers/rpc/__init__.py +5 -0
- web3/providers/rpc/async_rpc.py +73 -18
- web3/providers/rpc/rpc.py +73 -30
- web3/providers/rpc/utils.py +1 -13
- web3/scripts/install_pre_releases.py +33 -0
- web3/scripts/parse_pygeth_version.py +16 -0
- web3/testing.py +4 -4
- web3/tracing.py +9 -5
- web3/types.py +141 -74
- web3/utils/__init__.py +64 -5
- web3/utils/abi.py +790 -10
- web3/utils/address.py +8 -0
- web3/utils/async_exception_handling.py +20 -11
- web3/utils/caching.py +34 -4
- web3/utils/exception_handling.py +9 -12
- web3/utils/subscriptions.py +285 -0
- {web3-7.0.0b2.dist-info → web3-7.7.0.dist-info}/LICENSE +1 -1
- web3-7.7.0.dist-info/METADATA +130 -0
- web3-7.7.0.dist-info/RECORD +171 -0
- {web3-7.0.0b2.dist-info → web3-7.7.0.dist-info}/WHEEL +1 -1
- web3/_utils/caching.py +0 -155
- web3/_utils/contract_sources/contract_data/address_reflector.py +0 -29
- web3/_utils/module_testing/go_ethereum_personal_module.py +0 -300
- web3/_utils/request.py +0 -265
- web3-7.0.0b2.dist-info/METADATA +0 -106
- web3-7.0.0b2.dist-info/RECORD +0 -163
- /web3/_utils/{function_identifiers.py → abi_element_identifiers.py} +0 -0
- {web3-7.0.0b2.dist-info → web3-7.7.0.dist-info}/top_level.txt +0 -0
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
from typing import (
|
|
3
|
+
TYPE_CHECKING,
|
|
3
4
|
Any,
|
|
4
5
|
NoReturn,
|
|
5
6
|
Sequence,
|
|
6
|
-
|
|
7
|
+
cast,
|
|
7
8
|
)
|
|
8
9
|
|
|
9
10
|
from eth_typing import (
|
|
11
|
+
Address,
|
|
10
12
|
ChecksumAddress,
|
|
11
13
|
HexAddress,
|
|
12
14
|
HexStr,
|
|
@@ -23,10 +25,23 @@ from web3 import (
|
|
|
23
25
|
from web3._utils.ens import (
|
|
24
26
|
ens_addresses,
|
|
25
27
|
)
|
|
28
|
+
from web3.contract import (
|
|
29
|
+
Contract,
|
|
30
|
+
)
|
|
26
31
|
from web3.exceptions import (
|
|
27
32
|
InvalidAddress,
|
|
33
|
+
MethodNotSupported,
|
|
34
|
+
Web3ValueError,
|
|
35
|
+
)
|
|
36
|
+
from web3.types import (
|
|
37
|
+
BlockData,
|
|
28
38
|
)
|
|
29
39
|
|
|
40
|
+
if TYPE_CHECKING:
|
|
41
|
+
from web3.contract import ( # noqa: F401
|
|
42
|
+
AsyncContract,
|
|
43
|
+
)
|
|
44
|
+
|
|
30
45
|
|
|
31
46
|
class Web3ModuleTest:
|
|
32
47
|
def test_web3_client_version(self, w3: Web3) -> None:
|
|
@@ -223,16 +238,9 @@ class Web3ModuleTest:
|
|
|
223
238
|
),
|
|
224
239
|
),
|
|
225
240
|
)
|
|
226
|
-
@pytest.mark.parametrize(
|
|
227
|
-
"w3",
|
|
228
|
-
(
|
|
229
|
-
Web3,
|
|
230
|
-
AsyncWeb3,
|
|
231
|
-
),
|
|
232
|
-
)
|
|
233
241
|
def test_solidity_keccak(
|
|
234
242
|
self,
|
|
235
|
-
w3:
|
|
243
|
+
w3: "Web3",
|
|
236
244
|
types: Sequence[TypeStr],
|
|
237
245
|
values: Sequence[Any],
|
|
238
246
|
expected: HexBytes,
|
|
@@ -264,16 +272,9 @@ class Web3ModuleTest:
|
|
|
264
272
|
),
|
|
265
273
|
),
|
|
266
274
|
)
|
|
267
|
-
@pytest.mark.parametrize(
|
|
268
|
-
"w3",
|
|
269
|
-
(
|
|
270
|
-
Web3(),
|
|
271
|
-
AsyncWeb3(),
|
|
272
|
-
),
|
|
273
|
-
)
|
|
274
275
|
def test_solidity_keccak_ens(
|
|
275
276
|
self,
|
|
276
|
-
w3:
|
|
277
|
+
w3: "Web3",
|
|
277
278
|
types: Sequence[TypeStr],
|
|
278
279
|
values: Sequence[str],
|
|
279
280
|
expected: HexBytes,
|
|
@@ -313,3 +314,423 @@ class Web3ModuleTest:
|
|
|
313
314
|
|
|
314
315
|
def test_is_connected(self, w3: "Web3") -> None:
|
|
315
316
|
assert w3.is_connected()
|
|
317
|
+
|
|
318
|
+
def test_batch_requests(self, w3: "Web3", math_contract: Contract) -> None:
|
|
319
|
+
with w3.batch_requests() as batch:
|
|
320
|
+
batch.add(w3.eth.get_block(6))
|
|
321
|
+
batch.add(w3.eth.get_block(4))
|
|
322
|
+
batch.add(w3.eth.get_block(2))
|
|
323
|
+
batch.add(w3.eth.get_block(0))
|
|
324
|
+
batch.add(math_contract.functions.multiply7(0))
|
|
325
|
+
|
|
326
|
+
batch.add_mapping(
|
|
327
|
+
{
|
|
328
|
+
math_contract.functions.multiply7: [1, 2, 3],
|
|
329
|
+
w3.eth.get_block: [1, 3, 5],
|
|
330
|
+
}
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
assert len(batch._requests_info) == 11
|
|
334
|
+
responses = batch.execute()
|
|
335
|
+
assert len(responses) == 11
|
|
336
|
+
|
|
337
|
+
# assert proper batch cleanup after execution
|
|
338
|
+
assert batch._requests_info == []
|
|
339
|
+
assert not batch._provider._is_batching
|
|
340
|
+
|
|
341
|
+
# assert batch cannot be added to after execution
|
|
342
|
+
with pytest.raises(
|
|
343
|
+
Web3ValueError,
|
|
344
|
+
match="Batch has already been executed or cancelled",
|
|
345
|
+
):
|
|
346
|
+
batch.add(w3.eth.get_block(5))
|
|
347
|
+
|
|
348
|
+
# assert batch cannot be executed again
|
|
349
|
+
with pytest.raises(
|
|
350
|
+
Web3ValueError,
|
|
351
|
+
match="Batch has already been executed or cancelled",
|
|
352
|
+
):
|
|
353
|
+
batch.execute()
|
|
354
|
+
|
|
355
|
+
# assert can make a request after executing
|
|
356
|
+
block_num = w3.eth.block_number
|
|
357
|
+
assert isinstance(block_num, int)
|
|
358
|
+
|
|
359
|
+
first_four_responses: Sequence[BlockData] = cast(
|
|
360
|
+
Sequence[BlockData], responses[:4]
|
|
361
|
+
)
|
|
362
|
+
assert first_four_responses[0]["number"] == 6
|
|
363
|
+
assert first_four_responses[1]["number"] == 4
|
|
364
|
+
assert first_four_responses[2]["number"] == 2
|
|
365
|
+
assert first_four_responses[3]["number"] == 0
|
|
366
|
+
|
|
367
|
+
responses_five_through_eight: Sequence[int] = cast(
|
|
368
|
+
Sequence[int], responses[4:8]
|
|
369
|
+
)
|
|
370
|
+
assert responses_five_through_eight[0] == 0
|
|
371
|
+
assert responses_five_through_eight[1] == 7
|
|
372
|
+
assert responses_five_through_eight[2] == 14
|
|
373
|
+
assert responses_five_through_eight[3] == 21
|
|
374
|
+
|
|
375
|
+
last_three_responses: Sequence[BlockData] = cast(
|
|
376
|
+
Sequence[BlockData], responses[8:]
|
|
377
|
+
)
|
|
378
|
+
assert last_three_responses[0]["number"] == 1
|
|
379
|
+
assert last_three_responses[1]["number"] == 3
|
|
380
|
+
assert last_three_responses[2]["number"] == 5
|
|
381
|
+
|
|
382
|
+
def test_batch_requests_initialized_as_object(
|
|
383
|
+
self, w3: "Web3", math_contract: Contract
|
|
384
|
+
) -> None:
|
|
385
|
+
batch = w3.batch_requests()
|
|
386
|
+
batch.add(w3.eth.get_block(1))
|
|
387
|
+
batch.add(w3.eth.get_block(2))
|
|
388
|
+
batch.add(math_contract.functions.multiply7(0))
|
|
389
|
+
batch.add_mapping(
|
|
390
|
+
{math_contract.functions.multiply7: [1, 2], w3.eth.get_block: [3, 4]}
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
assert len(batch._requests_info) == 7
|
|
394
|
+
b1, b2, m0, m1, m2, b3, b4 = batch.execute()
|
|
395
|
+
|
|
396
|
+
# assert proper batch cleanup after execution
|
|
397
|
+
assert batch._requests_info == []
|
|
398
|
+
assert not batch._provider._is_batching
|
|
399
|
+
|
|
400
|
+
# assert batch cannot be added to after execution
|
|
401
|
+
with pytest.raises(
|
|
402
|
+
Web3ValueError,
|
|
403
|
+
match="Batch has already been executed or cancelled",
|
|
404
|
+
):
|
|
405
|
+
batch.add(w3.eth.get_block(5))
|
|
406
|
+
|
|
407
|
+
# assert batch cannot be executed again
|
|
408
|
+
with pytest.raises(
|
|
409
|
+
Web3ValueError,
|
|
410
|
+
match="Batch has already been executed or cancelled",
|
|
411
|
+
):
|
|
412
|
+
batch.execute()
|
|
413
|
+
|
|
414
|
+
# assert can make a request after executing
|
|
415
|
+
block_num = w3.eth.block_number
|
|
416
|
+
assert isinstance(block_num, int)
|
|
417
|
+
|
|
418
|
+
assert cast(BlockData, b1)["number"] == 1
|
|
419
|
+
assert cast(BlockData, b2)["number"] == 2
|
|
420
|
+
assert cast(int, m0) == 0
|
|
421
|
+
assert cast(int, m1) == 7
|
|
422
|
+
assert cast(int, m2) == 14
|
|
423
|
+
assert cast(BlockData, b3)["number"] == 3
|
|
424
|
+
assert cast(BlockData, b4)["number"] == 4
|
|
425
|
+
|
|
426
|
+
def test_batch_requests_clear(self, w3: "Web3") -> None:
|
|
427
|
+
with w3.batch_requests() as batch:
|
|
428
|
+
batch.add(w3.eth.get_block(1))
|
|
429
|
+
batch.add(w3.eth.get_block(2))
|
|
430
|
+
|
|
431
|
+
assert len(batch._requests_info) == 2
|
|
432
|
+
batch.clear()
|
|
433
|
+
assert batch._requests_info == []
|
|
434
|
+
|
|
435
|
+
batch.add(w3.eth.get_block(3))
|
|
436
|
+
batch.add(w3.eth.get_block(4))
|
|
437
|
+
|
|
438
|
+
r1, r2 = batch.execute()
|
|
439
|
+
|
|
440
|
+
assert cast(BlockData, r1)["number"] == 3
|
|
441
|
+
assert cast(BlockData, r2)["number"] == 4
|
|
442
|
+
|
|
443
|
+
new_batch = w3.batch_requests()
|
|
444
|
+
new_batch.add(w3.eth.get_block(5))
|
|
445
|
+
|
|
446
|
+
assert len(new_batch._requests_info) == 1
|
|
447
|
+
new_batch.clear()
|
|
448
|
+
assert new_batch._requests_info == []
|
|
449
|
+
|
|
450
|
+
new_batch.add(w3.eth.get_block(6))
|
|
451
|
+
(r3,) = new_batch.execute()
|
|
452
|
+
assert cast(BlockData, r3)["number"] == 6
|
|
453
|
+
|
|
454
|
+
def test_batch_requests_cancel(self, w3: "Web3") -> None:
|
|
455
|
+
# as context manager
|
|
456
|
+
with w3.batch_requests() as batch:
|
|
457
|
+
batch.add(w3.eth.get_block(1))
|
|
458
|
+
batch.cancel()
|
|
459
|
+
with pytest.raises(
|
|
460
|
+
Web3ValueError,
|
|
461
|
+
match="Batch has already been executed or cancelled",
|
|
462
|
+
):
|
|
463
|
+
batch.add(w3.eth.get_block(2))
|
|
464
|
+
with pytest.raises(
|
|
465
|
+
Web3ValueError,
|
|
466
|
+
match="Batch has already been executed or cancelled",
|
|
467
|
+
):
|
|
468
|
+
batch.execute()
|
|
469
|
+
|
|
470
|
+
# can make a request after cancelling
|
|
471
|
+
block_num = w3.eth.block_number
|
|
472
|
+
assert isinstance(block_num, int)
|
|
473
|
+
|
|
474
|
+
# as obj
|
|
475
|
+
new_batch = w3.batch_requests()
|
|
476
|
+
new_batch.add(w3.eth.get_block(1))
|
|
477
|
+
new_batch.cancel()
|
|
478
|
+
with pytest.raises(
|
|
479
|
+
Web3ValueError,
|
|
480
|
+
match="Batch has already been executed or cancelled",
|
|
481
|
+
):
|
|
482
|
+
new_batch.add(w3.eth.get_block(2))
|
|
483
|
+
with pytest.raises(
|
|
484
|
+
Web3ValueError,
|
|
485
|
+
match="Batch has already been executed or cancelled",
|
|
486
|
+
):
|
|
487
|
+
new_batch.execute()
|
|
488
|
+
|
|
489
|
+
# assert can make a request after cancelling
|
|
490
|
+
block_num = w3.eth.block_number
|
|
491
|
+
assert isinstance(block_num, int)
|
|
492
|
+
|
|
493
|
+
def test_batch_requests_raises_for_common_unsupported_methods(
|
|
494
|
+
self, w3: "Web3", math_contract: Contract
|
|
495
|
+
) -> None:
|
|
496
|
+
with w3.batch_requests() as batch:
|
|
497
|
+
with pytest.raises(MethodNotSupported, match="eth_sendTransaction"):
|
|
498
|
+
batch.add(w3.eth.send_transaction({}))
|
|
499
|
+
batch.execute()
|
|
500
|
+
|
|
501
|
+
with w3.batch_requests() as batch:
|
|
502
|
+
with pytest.raises(MethodNotSupported, match="eth_sendTransaction"):
|
|
503
|
+
batch.add(math_contract.functions.multiply7(1).transact({}))
|
|
504
|
+
batch.execute()
|
|
505
|
+
|
|
506
|
+
with w3.batch_requests() as batch:
|
|
507
|
+
with pytest.raises(MethodNotSupported, match="eth_sendRawTransaction"):
|
|
508
|
+
batch.add(w3.eth.send_raw_transaction(b""))
|
|
509
|
+
batch.execute()
|
|
510
|
+
|
|
511
|
+
with w3.batch_requests() as batch:
|
|
512
|
+
with pytest.raises(MethodNotSupported, match="eth_sign"):
|
|
513
|
+
batch.add(w3.eth.sign(Address(b"\x00" * 20)))
|
|
514
|
+
batch.execute()
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
# -- async -- #
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
class AsyncWeb3ModuleTest(Web3ModuleTest):
|
|
521
|
+
# Note: Any test that overrides the synchronous test from `Web3ModuleTest` with
|
|
522
|
+
# an asynchronous test should have the exact same name.
|
|
523
|
+
|
|
524
|
+
@pytest.mark.asyncio
|
|
525
|
+
async def test_web3_client_version(self, async_w3: AsyncWeb3) -> None: # type: ignore[override] # noqa: E501
|
|
526
|
+
client_version = await async_w3.client_version
|
|
527
|
+
self._check_web3_client_version(client_version)
|
|
528
|
+
|
|
529
|
+
@pytest.mark.asyncio
|
|
530
|
+
async def test_batch_requests( # type: ignore[override]
|
|
531
|
+
self, async_w3: AsyncWeb3, async_math_contract: "AsyncContract"
|
|
532
|
+
) -> None:
|
|
533
|
+
async with async_w3.batch_requests() as batch:
|
|
534
|
+
batch.add(async_w3.eth.get_block(6))
|
|
535
|
+
batch.add(async_w3.eth.get_block(4))
|
|
536
|
+
batch.add(async_w3.eth.get_block(2))
|
|
537
|
+
batch.add(async_w3.eth.get_block(0))
|
|
538
|
+
|
|
539
|
+
batch.add(async_math_contract.functions.multiply7(0))
|
|
540
|
+
|
|
541
|
+
batch.add_mapping(
|
|
542
|
+
{
|
|
543
|
+
async_math_contract.functions.multiply7: [1, 2, 3],
|
|
544
|
+
async_w3.eth.get_block: [1, 3, 5],
|
|
545
|
+
}
|
|
546
|
+
)
|
|
547
|
+
|
|
548
|
+
assert len(batch._async_requests_info) == 11
|
|
549
|
+
responses = await batch.async_execute()
|
|
550
|
+
assert len(responses) == 11
|
|
551
|
+
|
|
552
|
+
# assert proper batch cleanup after execution
|
|
553
|
+
assert batch._async_requests_info == []
|
|
554
|
+
assert not batch._provider._is_batching
|
|
555
|
+
|
|
556
|
+
# assert batch cannot be added to after execution
|
|
557
|
+
with pytest.raises(
|
|
558
|
+
Web3ValueError,
|
|
559
|
+
match="Batch has already been executed or cancelled",
|
|
560
|
+
):
|
|
561
|
+
batch.add(async_w3.eth.get_block(5))
|
|
562
|
+
|
|
563
|
+
# assert batch cannot be executed again
|
|
564
|
+
with pytest.raises(
|
|
565
|
+
Web3ValueError,
|
|
566
|
+
match="Batch has already been executed or cancelled",
|
|
567
|
+
):
|
|
568
|
+
await batch.async_execute()
|
|
569
|
+
|
|
570
|
+
# assert can make a request after executing
|
|
571
|
+
block_num = await async_w3.eth.block_number
|
|
572
|
+
assert isinstance(block_num, int)
|
|
573
|
+
|
|
574
|
+
first_four_responses: Sequence[BlockData] = cast(
|
|
575
|
+
Sequence[BlockData], responses[:4]
|
|
576
|
+
)
|
|
577
|
+
assert first_four_responses[0]["number"] == 6
|
|
578
|
+
assert first_four_responses[1]["number"] == 4
|
|
579
|
+
assert first_four_responses[2]["number"] == 2
|
|
580
|
+
assert first_four_responses[3]["number"] == 0
|
|
581
|
+
|
|
582
|
+
responses_five_through_eight: Sequence[int] = cast(
|
|
583
|
+
Sequence[int], responses[4:8]
|
|
584
|
+
)
|
|
585
|
+
assert responses_five_through_eight[0] == 0
|
|
586
|
+
assert responses_five_through_eight[1] == 7
|
|
587
|
+
assert responses_five_through_eight[2] == 14
|
|
588
|
+
assert responses_five_through_eight[3] == 21
|
|
589
|
+
|
|
590
|
+
last_three_responses: Sequence[BlockData] = cast(
|
|
591
|
+
Sequence[BlockData], responses[8:]
|
|
592
|
+
)
|
|
593
|
+
assert last_three_responses[0]["number"] == 1
|
|
594
|
+
assert last_three_responses[1]["number"] == 3
|
|
595
|
+
assert last_three_responses[2]["number"] == 5
|
|
596
|
+
|
|
597
|
+
@pytest.mark.asyncio
|
|
598
|
+
async def test_batch_requests_initialized_as_object( # type: ignore[override]
|
|
599
|
+
self, async_w3: AsyncWeb3, async_math_contract: "AsyncContract" # type: ignore[override] # noqa: E501
|
|
600
|
+
) -> None:
|
|
601
|
+
batch = async_w3.batch_requests()
|
|
602
|
+
batch.add(async_w3.eth.get_block(1))
|
|
603
|
+
batch.add(async_w3.eth.get_block(2))
|
|
604
|
+
batch.add(async_math_contract.functions.multiply7(0))
|
|
605
|
+
batch.add_mapping(
|
|
606
|
+
{
|
|
607
|
+
async_math_contract.functions.multiply7: [1, 2],
|
|
608
|
+
async_w3.eth.get_block: [3, 4],
|
|
609
|
+
}
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
assert len(batch._async_requests_info) == 7
|
|
613
|
+
b1, b2, m0, m1, m2, b3, b4 = await batch.async_execute()
|
|
614
|
+
|
|
615
|
+
# assert proper batch cleanup after execution
|
|
616
|
+
assert batch._async_requests_info == []
|
|
617
|
+
assert not batch._provider._is_batching
|
|
618
|
+
|
|
619
|
+
# assert batch cannot be added to after execution
|
|
620
|
+
with pytest.raises(
|
|
621
|
+
Web3ValueError,
|
|
622
|
+
match="Batch has already been executed or cancelled",
|
|
623
|
+
):
|
|
624
|
+
batch.add(async_w3.eth.get_block(5))
|
|
625
|
+
|
|
626
|
+
# assert batch cannot be executed again
|
|
627
|
+
with pytest.raises(
|
|
628
|
+
Web3ValueError,
|
|
629
|
+
match="Batch has already been executed or cancelled",
|
|
630
|
+
):
|
|
631
|
+
await batch.async_execute()
|
|
632
|
+
|
|
633
|
+
# assert can make a request after executing
|
|
634
|
+
block_num = await async_w3.eth.block_number
|
|
635
|
+
assert isinstance(block_num, int)
|
|
636
|
+
|
|
637
|
+
assert cast(BlockData, b1)["number"] == 1
|
|
638
|
+
assert cast(BlockData, b2)["number"] == 2
|
|
639
|
+
assert cast(int, m0) == 0
|
|
640
|
+
assert cast(int, m1) == 7
|
|
641
|
+
assert cast(int, m2) == 14
|
|
642
|
+
assert cast(BlockData, b3)["number"] == 3
|
|
643
|
+
assert cast(BlockData, b4)["number"] == 4
|
|
644
|
+
|
|
645
|
+
@pytest.mark.asyncio
|
|
646
|
+
async def test_batch_requests_clear(self, async_w3: AsyncWeb3) -> None: # type: ignore[override] # noqa: E501
|
|
647
|
+
async with async_w3.batch_requests() as batch:
|
|
648
|
+
batch.add(async_w3.eth.get_block(1))
|
|
649
|
+
batch.add(async_w3.eth.get_block(2))
|
|
650
|
+
|
|
651
|
+
assert len(batch._async_requests_info) == 2
|
|
652
|
+
batch.clear()
|
|
653
|
+
assert batch._async_requests_info == []
|
|
654
|
+
|
|
655
|
+
batch.add(async_w3.eth.get_block(3))
|
|
656
|
+
batch.add(async_w3.eth.get_block(4))
|
|
657
|
+
|
|
658
|
+
r1, r2 = await batch.async_execute()
|
|
659
|
+
|
|
660
|
+
assert cast(BlockData, r1)["number"] == 3
|
|
661
|
+
assert cast(BlockData, r2)["number"] == 4
|
|
662
|
+
|
|
663
|
+
new_batch = async_w3.batch_requests()
|
|
664
|
+
new_batch.add(async_w3.eth.get_block(5))
|
|
665
|
+
|
|
666
|
+
assert len(new_batch._async_requests_info) == 1
|
|
667
|
+
new_batch.clear()
|
|
668
|
+
assert new_batch._async_requests_info == []
|
|
669
|
+
|
|
670
|
+
new_batch.add(async_w3.eth.get_block(6))
|
|
671
|
+
(r3,) = await new_batch.async_execute()
|
|
672
|
+
assert cast(BlockData, r3)["number"] == 6
|
|
673
|
+
|
|
674
|
+
@pytest.mark.asyncio
|
|
675
|
+
async def test_batch_requests_cancel(self, async_w3: AsyncWeb3) -> None: # type: ignore[override] # noqa: E501
|
|
676
|
+
# as context manager
|
|
677
|
+
async with async_w3.batch_requests() as batch:
|
|
678
|
+
batch.add(async_w3.eth.get_block(1))
|
|
679
|
+
batch.cancel()
|
|
680
|
+
with pytest.raises(
|
|
681
|
+
Web3ValueError,
|
|
682
|
+
match="Batch has already been executed or cancelled",
|
|
683
|
+
):
|
|
684
|
+
batch.add(async_w3.eth.get_block(2))
|
|
685
|
+
with pytest.raises(
|
|
686
|
+
Web3ValueError,
|
|
687
|
+
match="Batch has already been executed or cancelled",
|
|
688
|
+
):
|
|
689
|
+
await batch.async_execute()
|
|
690
|
+
|
|
691
|
+
# can make a request after cancelling
|
|
692
|
+
block_num = await async_w3.eth.block_number
|
|
693
|
+
assert isinstance(block_num, int)
|
|
694
|
+
|
|
695
|
+
# as obj
|
|
696
|
+
new_batch = async_w3.batch_requests()
|
|
697
|
+
new_batch.add(async_w3.eth.get_block(1))
|
|
698
|
+
new_batch.cancel()
|
|
699
|
+
with pytest.raises(
|
|
700
|
+
Web3ValueError,
|
|
701
|
+
match="Batch has already been executed or cancelled",
|
|
702
|
+
):
|
|
703
|
+
new_batch.add(async_w3.eth.get_block(2))
|
|
704
|
+
with pytest.raises(
|
|
705
|
+
Web3ValueError,
|
|
706
|
+
match="Batch has already been executed or cancelled",
|
|
707
|
+
):
|
|
708
|
+
await new_batch.async_execute()
|
|
709
|
+
|
|
710
|
+
# can make a request after cancelling
|
|
711
|
+
block_num = await async_w3.eth.block_number
|
|
712
|
+
assert isinstance(block_num, int)
|
|
713
|
+
|
|
714
|
+
@pytest.mark.asyncio
|
|
715
|
+
async def test_batch_requests_raises_for_common_unsupported_methods( # type: ignore[override] # noqa: E501
|
|
716
|
+
self, async_w3: AsyncWeb3, async_math_contract: "AsyncContract" # type: ignore[override] # noqa: E501
|
|
717
|
+
) -> None:
|
|
718
|
+
async with async_w3.batch_requests() as batch:
|
|
719
|
+
with pytest.raises(MethodNotSupported, match="eth_sendTransaction"):
|
|
720
|
+
batch.add(async_w3.eth.send_transaction({}))
|
|
721
|
+
await batch.async_execute()
|
|
722
|
+
|
|
723
|
+
async with async_w3.batch_requests() as batch:
|
|
724
|
+
with pytest.raises(MethodNotSupported, match="eth_sendTransaction"):
|
|
725
|
+
batch.add(async_math_contract.functions.multiply7(1).transact({}))
|
|
726
|
+
await batch.async_execute()
|
|
727
|
+
|
|
728
|
+
async with async_w3.batch_requests() as batch:
|
|
729
|
+
with pytest.raises(MethodNotSupported, match="eth_sendRawTransaction"):
|
|
730
|
+
batch.add(async_w3.eth.send_raw_transaction(b""))
|
|
731
|
+
await batch.async_execute()
|
|
732
|
+
|
|
733
|
+
async with async_w3.batch_requests() as batch:
|
|
734
|
+
with pytest.raises(MethodNotSupported, match="eth_sign"):
|
|
735
|
+
batch.add(async_w3.eth.sign(Address(b"\x00" * 20)))
|
|
736
|
+
await batch.async_execute()
|
web3/_utils/normalizers.py
CHANGED
|
@@ -19,6 +19,7 @@ from eth_abi.grammar import (
|
|
|
19
19
|
parse,
|
|
20
20
|
)
|
|
21
21
|
from eth_typing import (
|
|
22
|
+
ABI,
|
|
22
23
|
ChecksumAddress,
|
|
23
24
|
HexStr,
|
|
24
25
|
TypeStr,
|
|
@@ -60,9 +61,7 @@ from web3._utils.validation import (
|
|
|
60
61
|
from web3.exceptions import (
|
|
61
62
|
InvalidAddress,
|
|
62
63
|
NameNotFound,
|
|
63
|
-
|
|
64
|
-
from web3.types import (
|
|
65
|
-
ABI,
|
|
64
|
+
Web3ValueError,
|
|
66
65
|
)
|
|
67
66
|
|
|
68
67
|
if TYPE_CHECKING:
|
|
@@ -151,7 +150,7 @@ def abi_bytes_to_hex(
|
|
|
151
150
|
|
|
152
151
|
num_bytes = abi_type.sub
|
|
153
152
|
if len(bytes_data) > num_bytes:
|
|
154
|
-
raise
|
|
153
|
+
raise Web3ValueError(
|
|
155
154
|
f"This value was expected to be at most {num_bytes} bytes, "
|
|
156
155
|
f"but instead was {len(bytes_data)}: {data!r}"
|
|
157
156
|
)
|
|
@@ -255,7 +254,9 @@ def normalize_abi(abi: Union[ABI, str]) -> ABI:
|
|
|
255
254
|
return cast(ABI, abi)
|
|
256
255
|
|
|
257
256
|
|
|
258
|
-
def normalize_address(
|
|
257
|
+
def normalize_address(
|
|
258
|
+
ens: ENS, address: Optional[ChecksumAddress]
|
|
259
|
+
) -> Union[ChecksumAddress, None]:
|
|
259
260
|
if address:
|
|
260
261
|
if is_ens_name(address):
|
|
261
262
|
validate_name_has_address(ens, address)
|
|
@@ -264,17 +265,18 @@ def normalize_address(ens: ENS, address: ChecksumAddress) -> ChecksumAddress:
|
|
|
264
265
|
return address
|
|
265
266
|
|
|
266
267
|
|
|
267
|
-
def normalize_address_no_ens(
|
|
268
|
+
def normalize_address_no_ens(
|
|
269
|
+
address: Optional[ChecksumAddress],
|
|
270
|
+
) -> Union[ChecksumAddress, None]:
|
|
268
271
|
if address:
|
|
269
272
|
validate_address(address)
|
|
270
273
|
return address
|
|
271
274
|
|
|
272
275
|
|
|
273
|
-
def normalize_bytecode(bytecode: bytes) -> HexBytes:
|
|
274
|
-
if bytecode:
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
return bytecode # type: ignore
|
|
276
|
+
def normalize_bytecode(bytecode: Optional[bytes]) -> Union[HexBytes, None]:
|
|
277
|
+
if bytecode is not None:
|
|
278
|
+
return HexBytes(bytecode)
|
|
279
|
+
return bytecode
|
|
278
280
|
|
|
279
281
|
|
|
280
282
|
# --- async -- #
|
web3/_utils/rpc_abi.py
CHANGED
|
@@ -24,6 +24,9 @@ from eth_utils.toolz import (
|
|
|
24
24
|
from web3._utils.abi import (
|
|
25
25
|
map_abi_data,
|
|
26
26
|
)
|
|
27
|
+
from web3.exceptions import (
|
|
28
|
+
Web3TypeError,
|
|
29
|
+
)
|
|
27
30
|
from web3.types import (
|
|
28
31
|
RPCEndpoint,
|
|
29
32
|
)
|
|
@@ -45,11 +48,11 @@ class RPC:
|
|
|
45
48
|
|
|
46
49
|
# eth
|
|
47
50
|
eth_accounts = RPCEndpoint("eth_accounts")
|
|
51
|
+
eth_blobBaseFee = RPCEndpoint("eth_blobBaseFee")
|
|
48
52
|
eth_blockNumber = RPCEndpoint("eth_blockNumber")
|
|
49
53
|
eth_call = RPCEndpoint("eth_call")
|
|
50
54
|
eth_createAccessList = RPCEndpoint("eth_createAccessList")
|
|
51
55
|
eth_chainId = RPCEndpoint("eth_chainId")
|
|
52
|
-
eth_coinbase = RPCEndpoint("eth_coinbase")
|
|
53
56
|
eth_estimateGas = RPCEndpoint("eth_estimateGas")
|
|
54
57
|
eth_feeHistory = RPCEndpoint("eth_feeHistory")
|
|
55
58
|
eth_maxPriorityFeePerGas = RPCEndpoint("eth_maxPriorityFeePerGas")
|
|
@@ -57,6 +60,7 @@ class RPC:
|
|
|
57
60
|
eth_getBalance = RPCEndpoint("eth_getBalance")
|
|
58
61
|
eth_getBlockByHash = RPCEndpoint("eth_getBlockByHash")
|
|
59
62
|
eth_getBlockByNumber = RPCEndpoint("eth_getBlockByNumber")
|
|
63
|
+
eth_getBlockReceipts = RPCEndpoint("eth_getBlockReceipts")
|
|
60
64
|
eth_getBlockTransactionCountByHash = RPCEndpoint(
|
|
61
65
|
"eth_getBlockTransactionCountByHash"
|
|
62
66
|
)
|
|
@@ -90,8 +94,6 @@ class RPC:
|
|
|
90
94
|
eth_getUncleCountByBlockHash = RPCEndpoint("eth_getUncleCountByBlockHash")
|
|
91
95
|
eth_getUncleCountByBlockNumber = RPCEndpoint("eth_getUncleCountByBlockNumber")
|
|
92
96
|
eth_getWork = RPCEndpoint("eth_getWork")
|
|
93
|
-
eth_hashrate = RPCEndpoint("eth_hashrate")
|
|
94
|
-
eth_mining = RPCEndpoint("eth_mining")
|
|
95
97
|
eth_newBlockFilter = RPCEndpoint("eth_newBlockFilter")
|
|
96
98
|
eth_newFilter = RPCEndpoint("eth_newFilter")
|
|
97
99
|
eth_newPendingTransactionFilter = RPCEndpoint("eth_newPendingTransactionFilter")
|
|
@@ -119,18 +121,6 @@ class RPC:
|
|
|
119
121
|
net_peerCount = RPCEndpoint("net_peerCount")
|
|
120
122
|
net_version = RPCEndpoint("net_version")
|
|
121
123
|
|
|
122
|
-
# personal
|
|
123
|
-
personal_ecRecover = RPCEndpoint("personal_ecRecover")
|
|
124
|
-
personal_importRawKey = RPCEndpoint("personal_importRawKey")
|
|
125
|
-
personal_listAccounts = RPCEndpoint("personal_listAccounts")
|
|
126
|
-
personal_listWallets = RPCEndpoint("personal_listWallets")
|
|
127
|
-
personal_lockAccount = RPCEndpoint("personal_lockAccount")
|
|
128
|
-
personal_newAccount = RPCEndpoint("personal_newAccount")
|
|
129
|
-
personal_sendTransaction = RPCEndpoint("personal_sendTransaction")
|
|
130
|
-
personal_sign = RPCEndpoint("personal_sign")
|
|
131
|
-
personal_signTypedData = RPCEndpoint("personal_signTypedData")
|
|
132
|
-
personal_unlockAccount = RPCEndpoint("personal_unlockAccount")
|
|
133
|
-
|
|
134
124
|
# testing
|
|
135
125
|
testing_timeTravel = RPCEndpoint("testing_timeTravel")
|
|
136
126
|
|
|
@@ -151,12 +141,16 @@ class RPC:
|
|
|
151
141
|
# web3
|
|
152
142
|
web3_clientVersion = RPCEndpoint("web3_clientVersion")
|
|
153
143
|
|
|
144
|
+
# debug
|
|
145
|
+
debug_traceTransaction = RPCEndpoint("debug_traceTransaction")
|
|
146
|
+
|
|
154
147
|
|
|
155
148
|
TRANSACTION_PARAMS_ABIS = {
|
|
156
149
|
"data": "bytes",
|
|
157
150
|
"from": "address",
|
|
158
151
|
"gas": "uint",
|
|
159
152
|
"gasPrice": "uint",
|
|
153
|
+
"maxFeePerBlobGas": "uint",
|
|
160
154
|
"maxFeePerGas": "uint",
|
|
161
155
|
"maxPriorityFeePerGas": "uint",
|
|
162
156
|
"nonce": "uint",
|
|
@@ -206,12 +200,6 @@ RPC_ABIS: Dict[str, Union[Sequence[Any], Dict[str, str]]] = {
|
|
|
206
200
|
"eth_signTypedData": ["address", None],
|
|
207
201
|
"eth_submitHashrate": ["uint", "bytes32"],
|
|
208
202
|
"eth_submitWork": ["bytes8", "bytes32", "bytes32"],
|
|
209
|
-
# personal
|
|
210
|
-
"personal_sendTransaction": TRANSACTION_PARAMS_ABIS,
|
|
211
|
-
"personal_lockAccount": ["address"],
|
|
212
|
-
"personal_unlockAccount": ["address", None, None],
|
|
213
|
-
"personal_sign": [None, "address", None],
|
|
214
|
-
"personal_signTypedData": [None, "address", None],
|
|
215
203
|
"trace_call": TRANSACTION_PARAMS_ABIS,
|
|
216
204
|
"trace_filter": TRACE_FILTER_PARAM_ABIS,
|
|
217
205
|
}
|
|
@@ -245,6 +233,6 @@ def abi_request_formatters(
|
|
|
245
233
|
single_dict_formatter = apply_abi_formatters_to_dict(normalizers, abi_types)
|
|
246
234
|
yield method, apply_formatter_at_index(single_dict_formatter, 0)
|
|
247
235
|
else:
|
|
248
|
-
raise
|
|
236
|
+
raise Web3TypeError(
|
|
249
237
|
f"ABI definitions must be a list or dictionary, got {abi_types!r}"
|
|
250
238
|
)
|
web3/_utils/threads.py
CHANGED
|
@@ -12,11 +12,12 @@ from typing import (
|
|
|
12
12
|
Any,
|
|
13
13
|
Callable,
|
|
14
14
|
Generic,
|
|
15
|
+
Literal,
|
|
15
16
|
Type,
|
|
16
17
|
)
|
|
17
18
|
|
|
18
|
-
from web3.
|
|
19
|
-
|
|
19
|
+
from web3.exceptions import (
|
|
20
|
+
Web3ValueError,
|
|
20
21
|
)
|
|
21
22
|
from web3.types import (
|
|
22
23
|
TReturn,
|
|
@@ -63,24 +64,24 @@ class Timeout(Exception):
|
|
|
63
64
|
@property
|
|
64
65
|
def expire_at(self) -> int:
|
|
65
66
|
if self.seconds is None:
|
|
66
|
-
raise
|
|
67
|
+
raise Web3ValueError(
|
|
67
68
|
"Timeouts with `seconds == None` do not have an expiration time"
|
|
68
69
|
)
|
|
69
70
|
elif self.begun_at is None:
|
|
70
|
-
raise
|
|
71
|
+
raise Web3ValueError("Timeout has not been started")
|
|
71
72
|
return self.begun_at + self.seconds
|
|
72
73
|
|
|
73
74
|
def start(self) -> None:
|
|
74
75
|
if self.is_running is not None:
|
|
75
|
-
raise
|
|
76
|
+
raise Web3ValueError("Timeout has already been started")
|
|
76
77
|
self.begun_at = time.time()
|
|
77
78
|
self.is_running = True
|
|
78
79
|
|
|
79
80
|
def check(self) -> None:
|
|
80
81
|
if self.is_running is None:
|
|
81
|
-
raise
|
|
82
|
+
raise Web3ValueError("Timeout has not been started")
|
|
82
83
|
elif self.is_running is False:
|
|
83
|
-
raise
|
|
84
|
+
raise Web3ValueError("Timeout has already been cancelled")
|
|
84
85
|
elif self.seconds is None:
|
|
85
86
|
return
|
|
86
87
|
elif time.time() > self.expire_at:
|