Skip to content

Commit 693e68f

Browse files
committed
Fix async issue with parsing block identifier
- ``BaseContractCaller`` used the sync version of ``parse_block_identifier`` which would render any calls inside it useless for ``AsyncContractCaller`` which inherits from it. I'm assuming we don't test all cases here. This commit splits the bulk of that logic out to the sync and async __init__ methods for contract caller and calls a more appropriate method for parsing the block identifier that doesn't involve an extra call. This reduces some of the intended functionality, but that wasn't working to begin with. This will need to be revised at some point to see if we can account for all desired cases within the async contract caller __init__.
1 parent 8e20a85 commit 693e68f

File tree

2 files changed

+42
-9
lines changed

2 files changed

+42
-9
lines changed

web3/_utils/contracts.py

+34-7
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ def parse_block_identifier(
422422
elif isinstance(block_identifier, bytes) or is_hex_encoded_block_hash(
423423
block_identifier
424424
):
425-
return w3.eth.get_block(HexBytes(block_identifier))["number"]
425+
return w3.eth.get_block(block_identifier)["number"]
426426
else:
427427
raise BlockNumberOutofRange
428428

@@ -438,23 +438,50 @@ def parse_block_identifier_int(w3: "Web3", block_identifier_int: int) -> BlockNu
438438
return BlockNumber(block_num)
439439

440440

441-
def async_parse_block_identifier(
441+
def parse_block_identifier_no_extra_call(
442+
async_w3: Union["Web3", "AsyncWeb3"], block_identifier: BlockIdentifier
443+
) -> BlockIdentifier:
444+
if block_identifier is None:
445+
return async_w3.eth.default_block
446+
elif isinstance(block_identifier, int) and block_identifier >= 0:
447+
return block_identifier
448+
elif block_identifier in ["latest", "earliest", "pending", "safe", "finalized"]:
449+
return block_identifier
450+
elif isinstance(block_identifier, bytes):
451+
return HexBytes(block_identifier)
452+
elif is_hex_encoded_block_hash(block_identifier):
453+
return HexStr(str(block_identifier))
454+
else:
455+
raise BlockNumberOutofRange
456+
457+
458+
async def async_parse_block_identifier(
442459
async_w3: "AsyncWeb3", block_identifier: BlockIdentifier
443460
) -> BlockIdentifier:
444461
if block_identifier is None:
445462
return async_w3.eth.default_block
446463
if isinstance(block_identifier, int):
447-
return async_parse_block_identifier_int(block_identifier)
464+
return await async_parse_block_identifier_int(async_w3, block_identifier)
448465
elif block_identifier in ["latest", "earliest", "pending", "safe", "finalized"]:
449466
return block_identifier
450467
elif isinstance(block_identifier, bytes) or is_hex_encoded_block_hash(
451468
block_identifier
452469
):
453-
return HexBytes(block_identifier)
470+
requested_block = await async_w3.eth.get_block(block_identifier)
471+
return requested_block["number"]
454472
else:
455473
raise BlockNumberOutofRange
456474

457475

458-
def async_parse_block_identifier_int(block_identifier_int: int) -> BlockNumber:
459-
assert block_identifier_int >= 0
460-
return BlockNumber(block_identifier_int)
476+
async def async_parse_block_identifier_int(
477+
async_w3: "AsyncWeb3", block_identifier_int: int
478+
) -> BlockNumber:
479+
if block_identifier_int >= 0:
480+
block_num = block_identifier_int
481+
else:
482+
last_block = await async_w3.eth.get_block("latest")
483+
last_block_num = last_block["number"]
484+
block_num = last_block_num + block_identifier_int + 1
485+
if block_num < 0:
486+
raise BlockNumberOutofRange
487+
return BlockNumber(block_num)

web3/contract/async_contract.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
)
3636
from web3._utils.contracts import (
3737
async_parse_block_identifier,
38+
parse_block_identifier_no_extra_call,
3839
)
3940
from web3._utils.datatypes import (
4041
PropertyCheckingFactory,
@@ -339,7 +340,7 @@ async def call(
339340
"""
340341
call_transaction = self._get_call_txparams(transaction)
341342

342-
block_id = async_parse_block_identifier(self.w3, block_identifier)
343+
block_id = await async_parse_block_identifier(self.w3, block_identifier)
343344

344345
return await async_call_contract_function(
345346
self.w3,
@@ -586,7 +587,12 @@ def __init__(
586587
decode_tuples=decode_tuples,
587588
)
588589

589-
block_id = async_parse_block_identifier(self.w3, block_identifier)
590+
# TODO: This is a hack to get around the fact that we can't call the
591+
# full async method from within a class's __init__ method. We'll need
592+
# to see if there's a way to account for all desired elif cases.
593+
block_id = parse_block_identifier_no_extra_call(
594+
self.w3, block_identifier
595+
)
590596
caller_method = partial(
591597
self.call_function,
592598
fn,

0 commit comments

Comments
 (0)