web3 7.11.1__py3-none-any.whl → 7.12.1__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/async_ens.py +2 -2
- ens/ens.py +2 -2
- ens/specs/.DS_Store +0 -0
- ens/utils.py +14 -3
- web3/_utils/abi.py +24 -20
- web3/_utils/batching.py +22 -68
- web3/_utils/caching/request_caching_validation.py +8 -4
- web3/_utils/decorators.py +12 -9
- web3/_utils/http_session_manager.py +18 -15
- web3/_utils/method_formatters.py +17 -24
- web3/_utils/module_testing/eth_module.py +39 -54
- web3/_utils/module_testing/web3_module.py +78 -4
- web3/_utils/validation.py +1 -1
- web3/contract/utils.py +20 -35
- web3/manager.py +108 -26
- web3/method.py +7 -7
- web3/providers/async_base.py +15 -1
- web3/providers/auto.py +28 -6
- web3/providers/base.py +18 -5
- web3/providers/ipc.py +4 -6
- web3/providers/legacy_websocket.py +4 -5
- web3/providers/persistent/persistent.py +110 -40
- web3/providers/persistent/request_processor.py +34 -51
- web3/providers/persistent/subscription_manager.py +12 -7
- web3/providers/rpc/async_rpc.py +7 -7
- web3/providers/rpc/rpc.py +6 -6
- web3/utils/subscriptions.py +7 -4
- {web3-7.11.1.dist-info → web3-7.12.1.dist-info}/METADATA +69 -56
- {web3-7.11.1.dist-info → web3-7.12.1.dist-info}/RECORD +32 -31
- {web3-7.11.1.dist-info → web3-7.12.1.dist-info}/WHEEL +1 -1
- {web3-7.11.1.dist-info → web3-7.12.1.dist-info/licenses}/LICENSE +0 -0
- {web3-7.11.1.dist-info → web3-7.12.1.dist-info}/top_level.txt +0 -0
|
@@ -37,6 +37,7 @@ from eth_utils import (
|
|
|
37
37
|
)
|
|
38
38
|
from eth_utils.toolz import (
|
|
39
39
|
assoc,
|
|
40
|
+
merge,
|
|
40
41
|
)
|
|
41
42
|
from hexbytes import (
|
|
42
43
|
HexBytes,
|
|
@@ -717,14 +718,12 @@ class AsyncEthModuleTest:
|
|
|
717
718
|
async_w3.middleware_onion.remove("signing")
|
|
718
719
|
|
|
719
720
|
@pytest.mark.asyncio
|
|
720
|
-
async def
|
|
721
|
+
async def test_async_sign_authorization_send_raw_and_send_set_code_transactions(
|
|
721
722
|
self,
|
|
722
723
|
async_w3: "AsyncWeb3",
|
|
723
724
|
keyfile_account_pkey: HexStr,
|
|
724
725
|
async_math_contract: "AsyncContract",
|
|
725
726
|
) -> None:
|
|
726
|
-
# TODO: remove blockNumber block_id from eth_call and eth_getCode calls once
|
|
727
|
-
# geth behavior for "latest" seems stable again.
|
|
728
727
|
keyfile_account = async_w3.eth.account.from_key(keyfile_account_pkey)
|
|
729
728
|
|
|
730
729
|
chain_id = await async_w3.eth.chain_id
|
|
@@ -752,16 +751,13 @@ class AsyncEthModuleTest:
|
|
|
752
751
|
"authorizationList": [signed_auth],
|
|
753
752
|
}
|
|
754
753
|
|
|
754
|
+
# test eth_sendRawTransaction
|
|
755
755
|
signed = keyfile_account.sign_transaction(txn)
|
|
756
756
|
tx_hash = await async_w3.eth.send_raw_transaction(signed.raw_transaction)
|
|
757
757
|
get_tx = await async_w3.eth.get_transaction(tx_hash)
|
|
758
|
-
|
|
759
|
-
tx_hash, timeout=10
|
|
760
|
-
)
|
|
758
|
+
await async_w3.eth.wait_for_transaction_receipt(tx_hash)
|
|
761
759
|
|
|
762
|
-
code = await async_w3.eth.get_code(
|
|
763
|
-
keyfile_account.address, block_identifier=tx_receipt["blockNumber"]
|
|
764
|
-
)
|
|
760
|
+
code = await async_w3.eth.get_code(keyfile_account.address)
|
|
765
761
|
assert code.to_0x_hex() == f"0xef0100{async_math_contract.address[2:].lower()}"
|
|
766
762
|
delegated = async_w3.eth.contract(
|
|
767
763
|
address=keyfile_account.address, abi=async_math_contract.abi
|
|
@@ -770,7 +766,7 @@ class AsyncEthModuleTest:
|
|
|
770
766
|
# assert the math counter is increased by 1337 only in delegated acct
|
|
771
767
|
assert await async_math_contract.functions.counter().call() == math_counter
|
|
772
768
|
delegated_call = await delegated.functions.counter().call(
|
|
773
|
-
block_identifier=
|
|
769
|
+
block_identifier="latest"
|
|
774
770
|
)
|
|
775
771
|
assert delegated_call == math_counter + 1337
|
|
776
772
|
|
|
@@ -790,21 +786,20 @@ class AsyncEthModuleTest:
|
|
|
790
786
|
"nonce": nonce + 3,
|
|
791
787
|
}
|
|
792
788
|
signed_reset_auth = keyfile_account.sign_authorization(reset_auth)
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
)
|
|
801
|
-
reset_tx_receipt = await async_w3.eth.wait_for_transaction_receipt(
|
|
802
|
-
reset_tx_hash, timeout=10
|
|
789
|
+
reset_code_txn = merge(
|
|
790
|
+
txn,
|
|
791
|
+
{
|
|
792
|
+
"from": keyfile_account.address,
|
|
793
|
+
"authorizationList": [signed_reset_auth],
|
|
794
|
+
"nonce": nonce + 2,
|
|
795
|
+
},
|
|
803
796
|
)
|
|
804
797
|
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
)
|
|
798
|
+
# test eth_sendTransaction
|
|
799
|
+
reset_tx_hash = await async_w3.eth.send_transaction(reset_code_txn)
|
|
800
|
+
await async_w3.eth.wait_for_transaction_receipt(reset_tx_hash, timeout=10)
|
|
801
|
+
|
|
802
|
+
reset_code = await async_w3.eth.get_code(keyfile_account.address)
|
|
808
803
|
assert reset_code == HexBytes("0x")
|
|
809
804
|
|
|
810
805
|
@pytest.mark.asyncio
|
|
@@ -3867,11 +3862,9 @@ class EthModuleTest:
|
|
|
3867
3862
|
# cleanup
|
|
3868
3863
|
w3.middleware_onion.remove("signing")
|
|
3869
3864
|
|
|
3870
|
-
def
|
|
3865
|
+
def test_sign_authorization_send_raw_and_send_set_code_transactions(
|
|
3871
3866
|
self, w3: "Web3", keyfile_account_pkey: HexStr, math_contract: "Contract"
|
|
3872
3867
|
) -> None:
|
|
3873
|
-
# TODO: remove blockNumber block_id from eth_call and eth_getCode calls once
|
|
3874
|
-
# geth behavior for "latest" seems stable again.
|
|
3875
3868
|
keyfile_account = w3.eth.account.from_key(keyfile_account_pkey)
|
|
3876
3869
|
|
|
3877
3870
|
chain_id = w3.eth.chain_id
|
|
@@ -3899,29 +3892,20 @@ class EthModuleTest:
|
|
|
3899
3892
|
"authorizationList": [signed_auth],
|
|
3900
3893
|
}
|
|
3901
3894
|
|
|
3895
|
+
# test eth_sendRawTransaction
|
|
3902
3896
|
signed = keyfile_account.sign_transaction(txn)
|
|
3903
|
-
|
|
3904
|
-
get_tx = w3.eth.get_transaction(
|
|
3905
|
-
|
|
3897
|
+
w3.eth.send_raw_transaction(signed.raw_transaction)
|
|
3898
|
+
get_tx = w3.eth.get_transaction(signed.hash)
|
|
3899
|
+
w3.eth.wait_for_transaction_receipt(signed.hash)
|
|
3906
3900
|
|
|
3907
|
-
code = w3.eth.get_code(
|
|
3908
|
-
keyfile_account.address, block_identifier=receipt["blockNumber"]
|
|
3909
|
-
)
|
|
3901
|
+
code = w3.eth.get_code(keyfile_account.address)
|
|
3910
3902
|
assert code.to_0x_hex() == f"0xef0100{math_contract.address[2:].lower()}"
|
|
3911
3903
|
delegated = w3.eth.contract(
|
|
3912
3904
|
address=keyfile_account.address, abi=math_contract.abi
|
|
3913
3905
|
)
|
|
3914
3906
|
# assert the math counter is increased by 1337 only in delegated acct
|
|
3915
|
-
assert (
|
|
3916
|
-
|
|
3917
|
-
block_identifier=receipt["blockNumber"]
|
|
3918
|
-
)
|
|
3919
|
-
== math_counter
|
|
3920
|
-
)
|
|
3921
|
-
assert (
|
|
3922
|
-
delegated.functions.counter().call(block_identifier=receipt["blockNumber"])
|
|
3923
|
-
== math_counter + 1337
|
|
3924
|
-
)
|
|
3907
|
+
assert math_contract.functions.counter().call() == math_counter
|
|
3908
|
+
assert delegated.functions.counter().call() == math_counter + 1337
|
|
3925
3909
|
|
|
3926
3910
|
assert len(get_tx["authorizationList"]) == 1
|
|
3927
3911
|
get_auth = get_tx["authorizationList"][0]
|
|
@@ -3932,26 +3916,27 @@ class EthModuleTest:
|
|
|
3932
3916
|
assert isinstance(get_auth["r"], HexBytes)
|
|
3933
3917
|
assert isinstance(get_auth["s"], HexBytes)
|
|
3934
3918
|
|
|
3935
|
-
# reset
|
|
3919
|
+
# reset code
|
|
3936
3920
|
reset_auth = {
|
|
3937
3921
|
"chainId": chain_id,
|
|
3938
3922
|
"address": "0x" + ("00" * 20),
|
|
3939
3923
|
"nonce": nonce + 3,
|
|
3940
3924
|
}
|
|
3941
3925
|
signed_reset_auth = keyfile_account.sign_authorization(reset_auth)
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
reset_tx_hash, timeout=10
|
|
3926
|
+
reset_code_txn = merge(
|
|
3927
|
+
txn,
|
|
3928
|
+
{
|
|
3929
|
+
"from": keyfile_account.address,
|
|
3930
|
+
"authorizationList": [signed_reset_auth],
|
|
3931
|
+
"nonce": nonce + 2,
|
|
3932
|
+
},
|
|
3950
3933
|
)
|
|
3951
3934
|
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
)
|
|
3935
|
+
# test eth_sendTransaction
|
|
3936
|
+
reset_tx_hash = w3.eth.send_transaction(reset_code_txn)
|
|
3937
|
+
w3.eth.wait_for_transaction_receipt(reset_tx_hash)
|
|
3938
|
+
|
|
3939
|
+
reset_code = w3.eth.get_code(keyfile_account.address)
|
|
3955
3940
|
assert reset_code == HexBytes("0x")
|
|
3956
3941
|
|
|
3957
3942
|
def test_eth_call(self, w3: "Web3", math_contract: "Contract") -> None:
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import pytest
|
|
2
|
+
import asyncio
|
|
3
|
+
import threading
|
|
4
|
+
import time
|
|
2
5
|
from typing import (
|
|
3
6
|
TYPE_CHECKING,
|
|
4
7
|
Any,
|
|
@@ -43,6 +46,9 @@ if TYPE_CHECKING:
|
|
|
43
46
|
)
|
|
44
47
|
|
|
45
48
|
|
|
49
|
+
SOME_BLOCK_KEYS = {"number", "hash", "parentHash", "stateRoot", "transactions"}
|
|
50
|
+
|
|
51
|
+
|
|
46
52
|
class Web3ModuleTest:
|
|
47
53
|
def test_web3_client_version(self, w3: Web3) -> None:
|
|
48
54
|
client_version = w3.client_version
|
|
@@ -336,7 +342,7 @@ class Web3ModuleTest:
|
|
|
336
342
|
|
|
337
343
|
# assert proper batch cleanup after execution
|
|
338
344
|
assert batch._requests_info == []
|
|
339
|
-
assert not
|
|
345
|
+
assert not w3.provider._is_batching
|
|
340
346
|
|
|
341
347
|
# assert batch cannot be added to after execution
|
|
342
348
|
with pytest.raises(
|
|
@@ -395,7 +401,7 @@ class Web3ModuleTest:
|
|
|
395
401
|
|
|
396
402
|
# assert proper batch cleanup after execution
|
|
397
403
|
assert batch._requests_info == []
|
|
398
|
-
assert not
|
|
404
|
+
assert not w3.provider._is_batching
|
|
399
405
|
|
|
400
406
|
# assert batch cannot be added to after execution
|
|
401
407
|
with pytest.raises(
|
|
@@ -513,6 +519,43 @@ class Web3ModuleTest:
|
|
|
513
519
|
batch.add(w3.eth.sign(Address(b"\x00" * 20)))
|
|
514
520
|
batch.execute()
|
|
515
521
|
|
|
522
|
+
def test_batch_requests_concurrently_with_regular_requests(
|
|
523
|
+
self, w3: "Web3"
|
|
524
|
+
) -> None:
|
|
525
|
+
num_requests = 40
|
|
526
|
+
responses = []
|
|
527
|
+
batch_response = []
|
|
528
|
+
|
|
529
|
+
def make_regular_requests() -> None:
|
|
530
|
+
for _ in range(num_requests):
|
|
531
|
+
responses.append(w3.eth.get_block(0))
|
|
532
|
+
time.sleep(0.01)
|
|
533
|
+
|
|
534
|
+
def make_batch_request() -> None:
|
|
535
|
+
with w3.batch_requests() as batch:
|
|
536
|
+
for _ in range(num_requests):
|
|
537
|
+
batch.add(w3.eth.get_block(0))
|
|
538
|
+
time.sleep(0.01)
|
|
539
|
+
batch_response.extend(batch.execute())
|
|
540
|
+
|
|
541
|
+
# split into threads
|
|
542
|
+
regular_thread = threading.Thread(target=make_regular_requests)
|
|
543
|
+
batch_thread = threading.Thread(target=make_batch_request)
|
|
544
|
+
|
|
545
|
+
regular_thread.start()
|
|
546
|
+
batch_thread.start()
|
|
547
|
+
|
|
548
|
+
# wait for threads to finish
|
|
549
|
+
regular_thread.join()
|
|
550
|
+
batch_thread.join()
|
|
551
|
+
assert not regular_thread.is_alive()
|
|
552
|
+
assert not batch_thread.is_alive()
|
|
553
|
+
|
|
554
|
+
assert len(responses) == num_requests
|
|
555
|
+
assert len(batch_response) == num_requests
|
|
556
|
+
assert all(SOME_BLOCK_KEYS.issubset(response.keys()) for response in responses)
|
|
557
|
+
assert set(responses) == set(batch_response)
|
|
558
|
+
|
|
516
559
|
|
|
517
560
|
# -- async -- #
|
|
518
561
|
|
|
@@ -551,7 +594,7 @@ class AsyncWeb3ModuleTest(Web3ModuleTest):
|
|
|
551
594
|
|
|
552
595
|
# assert proper batch cleanup after execution
|
|
553
596
|
assert batch._async_requests_info == []
|
|
554
|
-
assert not
|
|
597
|
+
assert not async_w3.provider._is_batching
|
|
555
598
|
|
|
556
599
|
# assert batch cannot be added to after execution
|
|
557
600
|
with pytest.raises(
|
|
@@ -614,7 +657,7 @@ class AsyncWeb3ModuleTest(Web3ModuleTest):
|
|
|
614
657
|
|
|
615
658
|
# assert proper batch cleanup after execution
|
|
616
659
|
assert batch._async_requests_info == []
|
|
617
|
-
assert not
|
|
660
|
+
assert not async_w3.provider._is_batching
|
|
618
661
|
|
|
619
662
|
# assert batch cannot be added to after execution
|
|
620
663
|
with pytest.raises(
|
|
@@ -734,3 +777,34 @@ class AsyncWeb3ModuleTest(Web3ModuleTest):
|
|
|
734
777
|
with pytest.raises(MethodNotSupported, match="eth_sign"):
|
|
735
778
|
batch.add(async_w3.eth.sign(Address(b"\x00" * 20)))
|
|
736
779
|
await batch.async_execute()
|
|
780
|
+
|
|
781
|
+
@pytest.mark.asyncio
|
|
782
|
+
async def test_batch_requests_concurrently_with_regular_requests( # type: ignore[override] # noqa: E501
|
|
783
|
+
self, async_w3: AsyncWeb3 # type: ignore[override]
|
|
784
|
+
) -> None:
|
|
785
|
+
responses = []
|
|
786
|
+
batch_response = []
|
|
787
|
+
|
|
788
|
+
num_blocks = await async_w3.eth.block_number
|
|
789
|
+
|
|
790
|
+
async def make_regular_requests() -> None:
|
|
791
|
+
for i in range(num_blocks):
|
|
792
|
+
responses.append(await async_w3.eth.get_block(i))
|
|
793
|
+
await asyncio.sleep(0.01)
|
|
794
|
+
|
|
795
|
+
async def make_batch_request() -> None:
|
|
796
|
+
async with async_w3.batch_requests() as batch:
|
|
797
|
+
for i in range(num_blocks):
|
|
798
|
+
batch.add(async_w3.eth.get_block(i))
|
|
799
|
+
await asyncio.sleep(0.01)
|
|
800
|
+
batch_response.extend(await batch.async_execute())
|
|
801
|
+
|
|
802
|
+
await asyncio.gather(
|
|
803
|
+
make_regular_requests(),
|
|
804
|
+
make_batch_request(),
|
|
805
|
+
)
|
|
806
|
+
|
|
807
|
+
assert len(responses) == num_blocks
|
|
808
|
+
assert len(batch_response) == num_blocks
|
|
809
|
+
assert all(SOME_BLOCK_KEYS.issubset(response.keys()) for response in responses)
|
|
810
|
+
assert set(responses) == set(batch_response)
|
web3/_utils/validation.py
CHANGED
|
@@ -396,7 +396,7 @@ def validate_rpc_response_and_raise_if_error(
|
|
|
396
396
|
|
|
397
397
|
response = apply_error_formatters(error_formatters, response)
|
|
398
398
|
if logger is not None:
|
|
399
|
-
logger.debug(
|
|
399
|
+
logger.debug("RPC error response: %s", response)
|
|
400
400
|
|
|
401
401
|
raise web3_rpc_error
|
|
402
402
|
|
web3/contract/utils.py
CHANGED
|
@@ -43,8 +43,8 @@ from web3._utils.abi import (
|
|
|
43
43
|
from web3._utils.async_transactions import (
|
|
44
44
|
async_fill_transaction_defaults,
|
|
45
45
|
)
|
|
46
|
-
from web3._utils.
|
|
47
|
-
|
|
46
|
+
from web3._utils.batching import (
|
|
47
|
+
BatchRequestInformation,
|
|
48
48
|
)
|
|
49
49
|
from web3._utils.contracts import (
|
|
50
50
|
prepare_transaction,
|
|
@@ -62,7 +62,6 @@ from web3.exceptions import (
|
|
|
62
62
|
from web3.types import (
|
|
63
63
|
ABIElementIdentifier,
|
|
64
64
|
BlockIdentifier,
|
|
65
|
-
RPCEndpoint,
|
|
66
65
|
StateOverride,
|
|
67
66
|
TContractEvent,
|
|
68
67
|
TContractFn,
|
|
@@ -175,10 +174,8 @@ def call_contract_function(
|
|
|
175
174
|
if abi_callable["type"] == "function":
|
|
176
175
|
output_types = get_abi_output_types(abi_callable)
|
|
177
176
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
BatchingReturnData: TypeAlias = Tuple[Tuple[RPCEndpoint, Any], Tuple[Any, ...]]
|
|
181
|
-
request_information = tuple(cast(BatchingReturnData, return_data))
|
|
177
|
+
if w3.provider._is_batching:
|
|
178
|
+
request_information = tuple(cast(BatchRequestInformation, return_data))
|
|
182
179
|
method_and_params = request_information[0]
|
|
183
180
|
|
|
184
181
|
# append return data formatting to result formatters
|
|
@@ -483,35 +480,23 @@ async def async_call_contract_function(
|
|
|
483
480
|
normalizers,
|
|
484
481
|
output_types,
|
|
485
482
|
)
|
|
486
|
-
if async_w3.provider.has_persistent_connection:
|
|
487
|
-
# get the current request id
|
|
488
|
-
provider = cast("PersistentConnectionProvider", async_w3.provider)
|
|
489
|
-
current_request_id = provider._batch_request_counter - 1
|
|
490
|
-
provider._request_processor.append_result_formatter_for_request(
|
|
491
|
-
current_request_id, contract_call_return_data_formatter
|
|
492
|
-
)
|
|
493
|
-
else:
|
|
494
|
-
BatchingReturnData: TypeAlias = Tuple[
|
|
495
|
-
Tuple[RPCEndpoint, Any], Tuple[Any, ...]
|
|
496
|
-
]
|
|
497
|
-
request_information = tuple(cast(BatchingReturnData, return_data))
|
|
498
|
-
method_and_params = request_information[0]
|
|
499
|
-
|
|
500
|
-
# append return data formatter to result formatters
|
|
501
|
-
current_response_formatters = request_information[1]
|
|
502
|
-
current_result_formatters = current_response_formatters[0]
|
|
503
|
-
updated_result_formatters = compose(
|
|
504
|
-
contract_call_return_data_formatter,
|
|
505
|
-
current_result_formatters,
|
|
506
|
-
)
|
|
507
|
-
response_formatters = (
|
|
508
|
-
updated_result_formatters, # result formatters
|
|
509
|
-
current_response_formatters[1], # error formatters
|
|
510
|
-
current_response_formatters[2], # null result formatters
|
|
511
|
-
)
|
|
512
|
-
return (method_and_params, response_formatters)
|
|
513
483
|
|
|
514
|
-
|
|
484
|
+
request_information = tuple(cast(BatchRequestInformation, return_data))
|
|
485
|
+
method_and_params = request_information[0]
|
|
486
|
+
|
|
487
|
+
# append return data formatter to result formatters
|
|
488
|
+
current_response_formatters = request_information[1]
|
|
489
|
+
current_result_formatters = current_response_formatters[0]
|
|
490
|
+
updated_result_formatters = compose(
|
|
491
|
+
contract_call_return_data_formatter,
|
|
492
|
+
current_result_formatters,
|
|
493
|
+
)
|
|
494
|
+
response_formatters = (
|
|
495
|
+
updated_result_formatters, # result formatters
|
|
496
|
+
current_response_formatters[1], # error formatters
|
|
497
|
+
current_response_formatters[2], # null result formatters
|
|
498
|
+
)
|
|
499
|
+
return (method_and_params, response_formatters)
|
|
515
500
|
|
|
516
501
|
try:
|
|
517
502
|
output_data = async_w3.codec.decode(output_types, return_data)
|
web3/manager.py
CHANGED
|
@@ -159,7 +159,7 @@ class RequestManager:
|
|
|
159
159
|
request_func = provider.request_func(
|
|
160
160
|
cast("Web3", self.w3), cast("MiddlewareOnion", self.middleware_onion)
|
|
161
161
|
)
|
|
162
|
-
self.logger.debug(
|
|
162
|
+
self.logger.debug("Making request. Method: %s", method)
|
|
163
163
|
return request_func(method, params)
|
|
164
164
|
|
|
165
165
|
async def _coro_make_request(
|
|
@@ -169,7 +169,7 @@ class RequestManager:
|
|
|
169
169
|
request_func = await provider.request_func(
|
|
170
170
|
cast("AsyncWeb3", self.w3), cast("MiddlewareOnion", self.middleware_onion)
|
|
171
171
|
)
|
|
172
|
-
self.logger.debug(
|
|
172
|
+
self.logger.debug("Making request. Method: %s", method)
|
|
173
173
|
return await request_func(method, params)
|
|
174
174
|
|
|
175
175
|
#
|
|
@@ -254,14 +254,14 @@ class RequestManager:
|
|
|
254
254
|
"""
|
|
255
255
|
Context manager for making batch requests
|
|
256
256
|
"""
|
|
257
|
-
if isinstance(
|
|
258
|
-
self.provider
|
|
259
|
-
|
|
257
|
+
if not isinstance(
|
|
258
|
+
self.provider, (AsyncJSONBaseProvider, JSONBaseProvider, AutoProvider)
|
|
259
|
+
):
|
|
260
260
|
raise Web3TypeError("Batch requests are not supported by this provider.")
|
|
261
261
|
return RequestBatcher(self.w3)
|
|
262
262
|
|
|
263
263
|
def _make_batch_request(
|
|
264
|
-
self, requests_info: List[Tuple[Tuple["RPCEndpoint", Any],
|
|
264
|
+
self, requests_info: List[Tuple[Tuple["RPCEndpoint", Any], Tuple[Any, ...]]]
|
|
265
265
|
) -> List[RPCResponse]:
|
|
266
266
|
"""
|
|
267
267
|
Make a batch request using the provider
|
|
@@ -291,7 +291,7 @@ class RequestManager:
|
|
|
291
291
|
async def _async_make_batch_request(
|
|
292
292
|
self,
|
|
293
293
|
requests_info: List[
|
|
294
|
-
Coroutine[Any, Any, Tuple[Tuple["RPCEndpoint", Any],
|
|
294
|
+
Coroutine[Any, Any, Tuple[Tuple["RPCEndpoint", Any], Tuple[Any]]]
|
|
295
295
|
],
|
|
296
296
|
) -> List[RPCResponse]:
|
|
297
297
|
"""
|
|
@@ -315,13 +315,6 @@ class RequestManager:
|
|
|
315
315
|
if isinstance(response, list):
|
|
316
316
|
# expected format
|
|
317
317
|
response = cast(List[RPCResponse], response)
|
|
318
|
-
if isinstance(self.provider, PersistentConnectionProvider):
|
|
319
|
-
# call _process_response for each response in the batch
|
|
320
|
-
return [
|
|
321
|
-
cast(RPCResponse, await self._process_response(resp))
|
|
322
|
-
for resp in response
|
|
323
|
-
]
|
|
324
|
-
|
|
325
318
|
formatted_responses = [
|
|
326
319
|
self._format_batched_response(info, resp)
|
|
327
320
|
for info, resp in zip(unpacked_requests_info, response)
|
|
@@ -331,6 +324,86 @@ class RequestManager:
|
|
|
331
324
|
# expect a single response with an error
|
|
332
325
|
raise_error_for_batch_response(response, self.logger)
|
|
333
326
|
|
|
327
|
+
async def _async_send_batch(
|
|
328
|
+
self, requests: List[Tuple["RPCEndpoint", Any]]
|
|
329
|
+
) -> List[RPCRequest]:
|
|
330
|
+
"""
|
|
331
|
+
Send a batch request via socket.
|
|
332
|
+
"""
|
|
333
|
+
if not isinstance(self._provider, PersistentConnectionProvider):
|
|
334
|
+
raise Web3TypeError(
|
|
335
|
+
"Only providers that maintain an open, persistent connection "
|
|
336
|
+
"can send batch requests."
|
|
337
|
+
)
|
|
338
|
+
send_func = await self._provider.send_batch_func(
|
|
339
|
+
cast("AsyncWeb3", self.w3),
|
|
340
|
+
cast("MiddlewareOnion", self.middleware_onion),
|
|
341
|
+
)
|
|
342
|
+
self.logger.debug(
|
|
343
|
+
"Sending batch request to open socket connection: %s",
|
|
344
|
+
self._provider.get_endpoint_uri_or_ipc_path(),
|
|
345
|
+
)
|
|
346
|
+
return await send_func(requests)
|
|
347
|
+
|
|
348
|
+
async def _async_recv_batch(self, requests: List[RPCRequest]) -> List[RPCResponse]:
|
|
349
|
+
"""
|
|
350
|
+
Receive a batch request via socket.
|
|
351
|
+
"""
|
|
352
|
+
if not isinstance(self._provider, PersistentConnectionProvider):
|
|
353
|
+
raise Web3TypeError(
|
|
354
|
+
"Only providers that maintain an open, persistent connection "
|
|
355
|
+
"can receive batch requests."
|
|
356
|
+
)
|
|
357
|
+
recv_func = await self._provider.recv_batch_func(
|
|
358
|
+
cast("AsyncWeb3", self.w3),
|
|
359
|
+
cast("MiddlewareOnion", self.middleware_onion),
|
|
360
|
+
)
|
|
361
|
+
self.logger.debug(
|
|
362
|
+
"Receiving batch request from open socket connection: %s",
|
|
363
|
+
self._provider.get_endpoint_uri_or_ipc_path(),
|
|
364
|
+
)
|
|
365
|
+
return await recv_func(requests)
|
|
366
|
+
|
|
367
|
+
async def _async_make_socket_batch_request(
|
|
368
|
+
self,
|
|
369
|
+
requests_info: List[
|
|
370
|
+
Coroutine[Any, Any, Tuple[Tuple["RPCEndpoint", Any], Tuple[Any, ...]]]
|
|
371
|
+
],
|
|
372
|
+
) -> List[RPCResponse]:
|
|
373
|
+
"""
|
|
374
|
+
Send and receive a batch request via a socket.
|
|
375
|
+
"""
|
|
376
|
+
if not isinstance(self._provider, PersistentConnectionProvider):
|
|
377
|
+
raise Web3TypeError(
|
|
378
|
+
"Only providers that maintain an open, persistent connection "
|
|
379
|
+
"can send and receive batch requests."
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
unpacked_requests_info = await asyncio.gather(*requests_info)
|
|
383
|
+
reqs = [req for req, _ in unpacked_requests_info]
|
|
384
|
+
response_formatters = [resp_f for _, resp_f in unpacked_requests_info]
|
|
385
|
+
|
|
386
|
+
requests = await self._async_send_batch(reqs)
|
|
387
|
+
|
|
388
|
+
for i, request in enumerate(requests):
|
|
389
|
+
self._provider._request_processor.cache_request_information(
|
|
390
|
+
request["id"],
|
|
391
|
+
request["method"],
|
|
392
|
+
request["params"],
|
|
393
|
+
response_formatters=response_formatters[i],
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
responses = await self._async_recv_batch(requests)
|
|
397
|
+
if isinstance(responses, list):
|
|
398
|
+
# expected format
|
|
399
|
+
return [
|
|
400
|
+
cast(RPCResponse, await self._process_response(resp))
|
|
401
|
+
for resp in responses
|
|
402
|
+
]
|
|
403
|
+
else:
|
|
404
|
+
# expect a single response with an error
|
|
405
|
+
raise_error_for_batch_response(responses, self.logger)
|
|
406
|
+
|
|
334
407
|
def _format_batched_response(
|
|
335
408
|
self,
|
|
336
409
|
requests_info: Tuple[Tuple[RPCEndpoint, Any], Sequence[Any]],
|
|
@@ -366,9 +439,12 @@ class RequestManager:
|
|
|
366
439
|
) -> RPCResponse:
|
|
367
440
|
provider = cast(PersistentConnectionProvider, self._provider)
|
|
368
441
|
self.logger.debug(
|
|
369
|
-
"Making request to open socket connection and waiting for response: "
|
|
370
|
-
|
|
371
|
-
|
|
442
|
+
"Making request to open socket connection and waiting for response: %s,\n"
|
|
443
|
+
" method: %s,\n"
|
|
444
|
+
" params: %s",
|
|
445
|
+
provider.get_endpoint_uri_or_ipc_path(),
|
|
446
|
+
method,
|
|
447
|
+
params,
|
|
372
448
|
)
|
|
373
449
|
rpc_request = await self.send(method, params)
|
|
374
450
|
provider._request_processor.cache_request_information(
|
|
@@ -388,9 +464,12 @@ class RequestManager:
|
|
|
388
464
|
middleware_onion,
|
|
389
465
|
)
|
|
390
466
|
self.logger.debug(
|
|
391
|
-
"Sending request to open socket connection: "
|
|
392
|
-
|
|
393
|
-
|
|
467
|
+
"Sending request to open socket connection: %s,\n"
|
|
468
|
+
" method: %s,\n"
|
|
469
|
+
" params: %s",
|
|
470
|
+
provider.get_endpoint_uri_or_ipc_path(),
|
|
471
|
+
method,
|
|
472
|
+
params,
|
|
394
473
|
)
|
|
395
474
|
return await send_func(method, params)
|
|
396
475
|
|
|
@@ -404,7 +483,8 @@ class RequestManager:
|
|
|
404
483
|
)
|
|
405
484
|
self.logger.debug(
|
|
406
485
|
"Getting response for request from open socket connection:\n"
|
|
407
|
-
|
|
486
|
+
" request: %s",
|
|
487
|
+
rpc_request,
|
|
408
488
|
)
|
|
409
489
|
response = await recv_func(rpc_request)
|
|
410
490
|
try:
|
|
@@ -417,8 +497,8 @@ class RequestManager:
|
|
|
417
497
|
async def recv(self) -> Union[RPCResponse, FormattedEthSubscriptionResponse]:
|
|
418
498
|
provider = cast(PersistentConnectionProvider, self._provider)
|
|
419
499
|
self.logger.debug(
|
|
420
|
-
"Getting next response from open socket connection: "
|
|
421
|
-
|
|
500
|
+
"Getting next response from open socket connection: %s",
|
|
501
|
+
provider.get_endpoint_uri_or_ipc_path(),
|
|
422
502
|
)
|
|
423
503
|
# pop from the queue since the listener task is responsible for reading
|
|
424
504
|
# directly from the socket
|
|
@@ -501,9 +581,11 @@ class RequestManager:
|
|
|
501
581
|
# subscription as it comes in
|
|
502
582
|
request_info.subscription_id = subscription_id
|
|
503
583
|
provider.logger.debug(
|
|
504
|
-
"Caching eth_subscription info:\n
|
|
505
|
-
|
|
506
|
-
|
|
584
|
+
"Caching eth_subscription info:\n"
|
|
585
|
+
" cache_key=%s,\n"
|
|
586
|
+
" request_info=%s",
|
|
587
|
+
cache_key,
|
|
588
|
+
request_info.__dict__,
|
|
507
589
|
)
|
|
508
590
|
self._request_processor._request_information_cache.cache(
|
|
509
591
|
cache_key, request_info
|
web3/method.py
CHANGED
|
@@ -165,8 +165,7 @@ class Method(Generic[TFunc]):
|
|
|
165
165
|
"usually attached to a web3 instance."
|
|
166
166
|
)
|
|
167
167
|
|
|
168
|
-
|
|
169
|
-
if hasattr(provider, "_is_batching") and provider._is_batching:
|
|
168
|
+
if module.w3.provider._is_batching:
|
|
170
169
|
if self.json_rpc_method in RPC_METHODS_UNSUPPORTED_DURING_BATCH:
|
|
171
170
|
raise MethodNotSupported(
|
|
172
171
|
f"Method `{self.json_rpc_method}` is not supported within a batch "
|
|
@@ -182,12 +181,13 @@ class Method(Generic[TFunc]):
|
|
|
182
181
|
@property
|
|
183
182
|
def method_selector_fn(
|
|
184
183
|
self,
|
|
185
|
-
) -> Callable[
|
|
184
|
+
) -> Callable[[], RPCEndpoint]:
|
|
186
185
|
"""Gets the method selector from the config."""
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
186
|
+
method = self.json_rpc_method
|
|
187
|
+
if callable(method):
|
|
188
|
+
return method
|
|
189
|
+
elif isinstance(method, str):
|
|
190
|
+
return lambda: method
|
|
191
191
|
raise Web3ValueError(
|
|
192
192
|
"``json_rpc_method`` config invalid. May be a string or function"
|
|
193
193
|
)
|