Skip to content

Commit d74d47d

Browse files
committed
reconcile changes with rebased async contract
1 parent d7fcac8 commit d74d47d

File tree

5 files changed

+110
-88
lines changed

5 files changed

+110
-88
lines changed

tests/integration/conftest.py

+8
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ def offchain_lookup_contract_factory(w3):
4949
return contract_factory
5050

5151

52+
@pytest.fixture(scope="module")
53+
def async_offchain_lookup_contract_factory(async_w3):
54+
contract_factory = async_w3.eth.contract(
55+
abi=OFFCHAIN_LOOKUP_ABI, bytecode=OFFCHAIN_LOOKUP_BYTECODE
56+
)
57+
return contract_factory
58+
59+
5260
@pytest.fixture(scope="module")
5361
def event_loop(request):
5462
loop = asyncio.get_event_loop_policy().new_event_loop()

tests/integration/go_ethereum/conftest.py

+7
Original file line numberDiff line numberDiff line change
@@ -241,3 +241,10 @@ def revert_contract(revert_contract_factory, geth_fixture_data):
241241
@pytest.fixture(scope="module")
242242
def offchain_lookup_contract(offchain_lookup_contract_factory, geth_fixture_data):
243243
return offchain_lookup_contract_factory(address=geth_fixture_data['offchain_lookup_address'])
244+
245+
246+
@pytest.fixture(scope="module")
247+
def async_offchain_lookup_contract(async_offchain_lookup_contract_factory, geth_fixture_data):
248+
return async_offchain_lookup_contract_factory(
249+
address=geth_fixture_data['offchain_lookup_address']
250+
)

web3/_utils/async_transactions.py

+8-9
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,29 @@
1313
from eth_typing import (
1414
URI,
1515
)
16+
from eth_utils.toolz import (
17+
curry,
18+
merge,
19+
)
1620

1721
from web3._utils.request import (
1822
async_get_json_from_client_response,
1923
async_get_response_from_get_request,
2024
async_get_response_from_post_request,
2125
)
22-
from web3._utils.type_conversion_utils import (
26+
from web3._utils.type_conversion import (
2327
to_bytes_if_hex,
2428
to_hex_if_bytes,
2529
)
26-
from web3.exceptions import (
27-
ValidationError,
28-
)
29-
from eth_utils.toolz import (
30-
curry,
31-
merge,
32-
)
33-
3430
from web3._utils.utility_methods import (
3531
any_in_dict,
3632
)
3733
from web3.constants import (
3834
DYNAMIC_FEE_TXN_PARAMS,
3935
)
36+
from web3.exceptions import (
37+
ValidationError,
38+
)
4039
from web3.types import (
4140
BlockIdentifier,
4241
TxParams,

web3/_utils/module_testing/eth_module.py

+63-64
Original file line numberDiff line numberDiff line change
@@ -760,91 +760,97 @@ async def test_eth_call_revert_without_msg(
760760
async def test_eth_call_offchain_lookup(
761761
self,
762762
async_w3: "Web3",
763-
offchain_lookup_contract: "Contract",
763+
async_offchain_lookup_contract: "Contract",
764764
unlocked_account: ChecksumAddress,
765765
monkeypatch: "MonkeyPatch",
766766
) -> None:
767-
normalized_contract_address = to_hex_if_bytes(offchain_lookup_contract.address).lower()
767+
normalized_contract_address = to_hex_if_bytes(
768+
async_offchain_lookup_contract.address
769+
).lower()
770+
768771
async_mock_offchain_lookup_request_response(
769772
monkeypatch,
770773
mocked_request_url=f'https://web3.py/gateway/{normalized_contract_address}/{OFFCHAIN_LOOKUP_TEST_DATA}.json', # noqa: E501
771774
mocked_json_data=WEB3PY_AS_HEXBYTES,
772775
)
773-
# TODO: change to contract call when async Contract is supported
774-
tx = {
775-
'to': offchain_lookup_contract.address,
776-
'data': '0x6337ed58000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001474657374206f6666636861696e206c6f6f6b7570000000000000000000000000' # noqa: E501
777-
}
778-
response = await async_w3.eth.call(tx) # type: ignore
779-
response_as_bytes = async_w3.codec.decode_abi(['bytes'], response)[0]
780-
decoded_as_string = async_w3.codec.decode_abi(['string'], response_as_bytes)[0]
781-
assert decoded_as_string == 'web3py'
776+
response_caller = await async_offchain_lookup_contract.caller().testOffchainLookup( # noqa: E501 type: ignore
777+
OFFCHAIN_LOOKUP_TEST_DATA
778+
)
779+
response_function_call = await async_offchain_lookup_contract.functions.testOffchainLookup( # noqa: E501 type: ignore
780+
OFFCHAIN_LOOKUP_TEST_DATA
781+
).call()
782+
assert async_w3.codec.decode_abi(['string'], response_caller)[0] == 'web3py'
783+
assert async_w3.codec.decode_abi(['string'], response_function_call)[0] == 'web3py'
782784

783785
@pytest.mark.asyncio
784-
async def test_eth_call_offchain_lookup_raises_when_ccip_read_is_disabled(
785-
self, async_w3: "Web3", offchain_lookup_contract: "Contract",
786+
async def test_eth_call_offchain_lookup_raises_when_ccip_read_is_disabled_yy(
787+
self, async_w3: "Web3", async_offchain_lookup_contract: "Contract",
786788
) -> None:
787-
# TODO: change to contract call when async Contract is supported
788-
tx = {
789-
'to': offchain_lookup_contract.address,
790-
'data': '0x6337ed58000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001474657374206f6666636861696e206c6f6f6b7570000000000000000000000000' # noqa: E501
791-
}
792789
with pytest.raises(OffchainLookup):
793-
await async_w3.eth.call(tx, ccip_read_enabled=False) # type: ignore
790+
# test AsyncContractCaller
791+
await async_offchain_lookup_contract.caller(ccip_read_enabled=False).testOffchainLookup( # noqa: E501 type: ignore
792+
OFFCHAIN_LOOKUP_TEST_DATA
793+
)
794+
with pytest.raises(OffchainLookup):
795+
# test AsyncContractFunction call
796+
await async_offchain_lookup_contract.functions.testOffchainLookup(
797+
OFFCHAIN_LOOKUP_TEST_DATA
798+
).call(ccip_read_enabled=False)
794799

795800
@pytest.mark.asyncio
796801
@pytest.mark.parametrize("max_redirects", range(-4, 4))
797802
async def test_eth_call_offchain_lookup_raises_if_max_redirects_is_less_than_4(
798803
self,
799804
async_w3: "Web3",
800-
offchain_lookup_contract: "Contract",
805+
async_offchain_lookup_contract: "Contract",
801806
max_redirects: int,
802807
) -> None:
803808
default_max_redirects = async_w3.provider.ccip_read_max_redirects
804-
tx = {
805-
'to': offchain_lookup_contract.address,
806-
'data': '0x6337ed58000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001474657374206f6666636861696e206c6f6f6b7570000000000000000000000000' # noqa: E501
807-
}
809+
808810
async_w3.provider.ccip_read_max_redirects = max_redirects
809811
with pytest.raises(ValueError, match="at least 4"):
810-
await async_w3.eth.call(tx) # type: ignore
812+
await async_offchain_lookup_contract.caller().testOffchainLookup(
813+
OFFCHAIN_LOOKUP_TEST_DATA
814+
)
811815

812816
async_w3.provider.ccip_read_max_redirects = default_max_redirects # cleanup
813817

814818
@pytest.mark.asyncio
815819
async def test_eth_call_offchain_lookup_raises_for_improperly_formatted_rest_request_response(
816820
self,
817821
async_w3: "Web3",
818-
offchain_lookup_contract: "Contract",
822+
async_offchain_lookup_contract: "Contract",
819823
unlocked_account: ChecksumAddress,
820824
monkeypatch: "MonkeyPatch",
821825
) -> None:
822-
normalized_contract_address = to_hex_if_bytes(offchain_lookup_contract.address).lower()
826+
normalized_contract_address = to_hex_if_bytes(
827+
async_offchain_lookup_contract.address
828+
).lower()
829+
823830
async_mock_offchain_lookup_request_response(
824831
monkeypatch,
825832
mocked_request_url=f'https://web3.py/gateway/{normalized_contract_address}/{OFFCHAIN_LOOKUP_TEST_DATA}.json', # noqa: E501
826833
mocked_json_data=WEB3PY_AS_HEXBYTES,
827834
json_data_field='not_data',
828835
)
829-
# TODO: change to contract call when async Contract is supported
830-
tx = {
831-
'to': offchain_lookup_contract.address,
832-
'data': '0x6337ed58000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001474657374206f6666636861696e206c6f6f6b7570000000000000000000000000' # noqa: E501
833-
}
834836
with pytest.raises(ValidationError, match="missing 'data' field"):
835-
await async_w3.eth.call(tx) # type: ignore
837+
await async_offchain_lookup_contract.caller().testOffchainLookup(
838+
OFFCHAIN_LOOKUP_TEST_DATA
839+
)
836840

837841
@pytest.mark.asyncio
838842
@pytest.mark.parametrize('status_code_non_4xx_error', [100, 300, 500, 600])
839843
async def test_eth_call_offchain_lookup_tries_next_url_for_non_4xx_error_status_and_tests_POST(
840844
self,
841845
async_w3: "Web3",
842-
offchain_lookup_contract: "Contract",
846+
async_offchain_lookup_contract: "Contract",
843847
unlocked_account: ChecksumAddress,
844848
monkeypatch: "MonkeyPatch",
845849
status_code_non_4xx_error: int,
846850
) -> None:
847-
normalized_contract_address = to_hex_if_bytes(offchain_lookup_contract.address).lower()
851+
normalized_contract_address = to_hex_if_bytes(
852+
async_offchain_lookup_contract.address
853+
).lower()
848854

849855
# The next url in our test contract doesn't contain '{data}', triggering the POST request
850856
# logic. The idea here is to return a bad status for the first url (GET) and a success
@@ -865,73 +871,66 @@ async def test_eth_call_offchain_lookup_tries_next_url_for_non_4xx_error_status_
865871
sender=normalized_contract_address,
866872
calldata=OFFCHAIN_LOOKUP_TEST_DATA,
867873
)
868-
# TODO: change to contract call when async Contract is supported
869-
tx = {
870-
'to': offchain_lookup_contract.address,
871-
'data': '0x6337ed58000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001474657374206f6666636861696e206c6f6f6b7570000000000000000000000000' # noqa: E501
872-
}
873-
response = await async_w3.eth.call(tx) # type: ignore
874-
response_as_bytes = async_w3.codec.decode_abi(['bytes'], response)[0]
875-
decoded_as_string = async_w3.codec.decode_abi(['string'], response_as_bytes)[0]
876-
assert decoded_as_string == 'web3py'
874+
response = await async_offchain_lookup_contract.caller().testOffchainLookup(
875+
OFFCHAIN_LOOKUP_TEST_DATA
876+
)
877+
assert async_w3.codec.decode_abi(['string'], response)[0] == 'web3py'
877878

878879
@pytest.mark.asyncio
879880
@pytest.mark.parametrize('status_code_4xx_error', [400, 410, 450, 499])
880881
async def test_eth_call_offchain_lookup_calls_raise_for_status_for_4xx_status_code(
881882
self,
882883
async_w3: "Web3",
883-
offchain_lookup_contract: "Contract",
884+
async_offchain_lookup_contract: "Contract",
884885
unlocked_account: ChecksumAddress,
885886
monkeypatch: "MonkeyPatch",
886887
status_code_4xx_error: int,
887888
) -> None:
888-
normalized_contract_address = to_hex_if_bytes(offchain_lookup_contract.address).lower()
889+
normalized_contract_address = to_hex_if_bytes(
890+
async_offchain_lookup_contract.address
891+
).lower()
892+
889893
async_mock_offchain_lookup_request_response(
890894
monkeypatch,
891895
mocked_request_url=f'https://web3.py/gateway/{normalized_contract_address}/{OFFCHAIN_LOOKUP_TEST_DATA}.json', # noqa: E501
892896
mocked_status_code=status_code_4xx_error,
893897
mocked_json_data=WEB3PY_AS_HEXBYTES,
894898
)
895899
with pytest.raises(Exception, match="called raise_for_status\\(\\)"):
896-
# TODO: change to contract call when async Contract is supported
897-
tx = {
898-
'to': offchain_lookup_contract.address,
899-
'data': '0x6337ed58000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001474657374206f6666636861696e206c6f6f6b7570000000000000000000000000' # noqa: E501
900-
}
901-
await async_w3.eth.call(tx) # type: ignore
900+
await async_offchain_lookup_contract.caller().testOffchainLookup(
901+
OFFCHAIN_LOOKUP_TEST_DATA
902+
)
902903

903904
@pytest.mark.asyncio
904905
async def test_eth_call_offchain_lookup_raises_when_all_supplied_urls_fail(
905-
self, async_w3: "Web3", offchain_lookup_contract: "Contract",
906+
self, async_w3: "Web3", async_offchain_lookup_contract: "Contract",
906907
) -> None:
907908
# GET and POST requests should fail since responses are not mocked
908909
with pytest.raises(
909910
MultipleFailedRequests, match="Offchain lookup failed for supplied urls"
910911
):
911-
# TODO: change to contract call when async Contract is supported
912-
tx = {
913-
'to': offchain_lookup_contract.address,
914-
'data': '0x6337ed58000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001474657374206f6666636861696e206c6f6f6b7570000000000000000000000000' # noqa: E501
915-
}
916-
await async_w3.eth.call(tx) # type: ignore
912+
await async_offchain_lookup_contract.caller().testOffchainLookup(
913+
OFFCHAIN_LOOKUP_TEST_DATA
914+
)
917915

918916
@pytest.mark.asyncio
919917
async def test_eth_call_continuous_offchain_lookup_raises_with_too_many_requests(
920918
self,
921919
async_w3: "Web3",
922-
offchain_lookup_contract: "Contract",
920+
async_offchain_lookup_contract: "Contract",
923921
unlocked_account: ChecksumAddress,
924922
monkeypatch: "MonkeyPatch",
925923
) -> None:
926-
normalized_contract_address = to_hex_if_bytes(offchain_lookup_contract.address).lower()
924+
normalized_contract_address = to_hex_if_bytes(
925+
async_offchain_lookup_contract.address
926+
).lower()
927+
927928
async_mock_offchain_lookup_request_response(
928929
monkeypatch,
929930
mocked_request_url=f'https://web3.py/gateway/{normalized_contract_address}/0x.json',
930931
)
931932
with pytest.raises(TooManyRequests, match="Too many CCIP read redirects"):
932-
# TODO: change to contract call when async Contract is supported
933-
tx = {'to': offchain_lookup_contract.address, 'data': '0x09a3c01b'}
934-
await async_w3.eth.call(tx) # type: ignore
933+
await async_offchain_lookup_contract.caller().continuousOffchainLookup() # noqa: E501 type: ignore
935934

936935
@pytest.mark.asyncio
937936
async def test_async_eth_hashrate(

web3/contract.py

+24-15
Original file line numberDiff line numberDiff line change
@@ -1404,6 +1404,7 @@ async def call(
14041404
self.contract_abi,
14051405
self.abi,
14061406
state_override,
1407+
ccip_read_enabled,
14071408
*self.args,
14081409
**self.kwargs
14091410
)
@@ -1878,11 +1879,16 @@ def call_function(
18781879
*args: Any,
18791880
transaction: Optional[TxParams] = None,
18801881
block_identifier: BlockIdentifier = 'latest',
1882+
ccip_read_enabled: bool = True,
18811883
**kwargs: Any
18821884
) -> Any:
18831885
if transaction is None:
18841886
transaction = {}
1885-
return fn(*args, **kwargs).call(transaction, block_identifier)
1887+
return fn(*args, **kwargs).call(
1888+
transaction=transaction,
1889+
block_identifier=block_identifier,
1890+
ccip_read_enabled=ccip_read_enabled,
1891+
)
18861892

18871893

18881894
class ContractCaller(BaseContractCaller):
@@ -1896,19 +1902,20 @@ def __init__(
18961902
ccip_read_enabled: bool = True,
18971903
) -> None:
18981904
super().__init__(
1899-
abi,
1900-
w3,
1901-
address,
1902-
transaction,
1903-
block_identifier,
1904-
ccip_read_enabled,
1905-
ContractFunction,
1905+
abi=abi,
1906+
w3=w3,
1907+
address=address,
1908+
transaction=transaction,
1909+
block_identifier=block_identifier,
1910+
ccip_read_enabled=ccip_read_enabled,
1911+
contract_function_class=ContractFunction,
19061912
)
19071913

19081914
def __call__(
19091915
self,
19101916
transaction: Optional[TxParams] = None,
19111917
block_identifier: BlockIdentifier = 'latest',
1918+
state_override: Optional[CallOverride] = None,
19121919
ccip_read_enabled: bool = True,
19131920
) -> 'ContractCaller':
19141921
if transaction is None:
@@ -1935,13 +1942,13 @@ def __init__(
19351942
ccip_read_enabled: bool = True,
19361943
) -> None:
19371944
super().__init__(
1938-
abi,
1939-
w3,
1940-
address,
1941-
transaction,
1942-
block_identifier,
1943-
ccip_read_enabled,
1944-
AsyncContractFunction
1945+
abi=abi,
1946+
w3=w3,
1947+
address=address,
1948+
transaction=transaction,
1949+
block_identifier=block_identifier,
1950+
ccip_read_enabled=ccip_read_enabled,
1951+
contract_function_class=AsyncContractFunction,
19451952
)
19461953

19471954
def __call__(
@@ -2062,6 +2069,7 @@ async def async_call_contract_function(
20622069
contract_abi: Optional[ABI] = None,
20632070
fn_abi: Optional[ABIFunction] = None,
20642071
state_override: Optional[CallOverride] = None,
2072+
ccip_read_enabled: bool = True,
20652073
*args: Any,
20662074
**kwargs: Any) -> Any:
20672075
"""
@@ -2083,6 +2091,7 @@ async def async_call_contract_function(
20832091
call_transaction,
20842092
block_identifier=block_id,
20852093
state_override=state_override,
2094+
ccip_read_enabled=ccip_read_enabled,
20862095
)
20872096

20882097
if fn_abi is None:

0 commit comments

Comments
 (0)