Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Call contract method with blockhash requires fetching block number #3646

Open
F4ever opened this issue Mar 18, 2025 · 3 comments
Open

Call contract method with blockhash requires fetching block number #3646

F4ever opened this issue Mar 18, 2025 · 3 comments

Comments

@F4ever
Copy link

F4ever commented Mar 18, 2025

What feature should we add?

Hi everyone!

For security reasons, we're calling contracts using block hashes and avoiding block numbers to ensure that we don't receive responses from a fork.

However, the contract method makes an additional request to the node to retrieve the block number with the block hash, increasing node load and making an unnecessary request. See here:
https://github.com/ethereum/web3.py/blob/main/web3/contract/contract.py#L287

Would it be possible to modify the parse_block_identifier function to avoid this additional request?
https://github.com/ethereum/web3.py/blob/main/web3/_utils/contracts.py#L349

e.g.

def parse_block_identifier(
    w3: "Web3", block_identifier: Optional[BlockIdentifier]
) -> BlockIdentifier:
    if block_identifier is None:
        return w3.eth.default_block
    if isinstance(block_identifier, int):
        return parse_block_identifier_int(w3, block_identifier)
    elif block_identifier in ["latest", "earliest", "pending", "safe", "finalized"]:
        return block_identifier
    elif isinstance(block_identifier, bytes) or is_hex_encoded_block_hash(
        block_identifier
    ):
        return to_hex_if_bytes(block_identifier)
    else:
        raise BlockNumberOutOfRange

Related to:
#2816

@fselmo
Copy link
Collaborator

fselmo commented Mar 24, 2025

Hey @F4ever, thanks for the issue. Unfortunately, eth_call does not accept blockhashes directly. It uses the default block parameter, which only accepts string block identifiers or block number.

@fselmo fselmo closed this as not planned Won't fix, can't repro, duplicate, stale Mar 24, 2025
@F4ever
Copy link
Author

F4ever commented Mar 24, 2025

Hey @fselmo, thanks for responding!

In practice, I haven’t encountered a single node that doesn’t support requests by block hash. However, there can be limitations on the client side — for example, block hashes may only be cached for the most recent N blocks. I believe such edge cases should be handled at the application level.

It's true that block hashes aren’t explicitly mentioned in the spec, but that doesn’t mean we shouldn’t support the described feature.

This library doesn’t aim to implement the interface 1:1 — and that’s perfectly fine. It was designed to simplify interaction with web3, not just serve as a thin wrapper around RPC requests.

For example, according to the documentation, Web3.py should accept a block number as a hex string for the block_identifier parameter. However, the following code results in an error:

# 0x1510FA4 == 22089636
deposit_contract.get_deposit_root('0x1510FA4')

Traceback (most recent call last):
  File "/Users/f4ever/Library/Caches/pypoetry/virtualenvs/py3.13/lib/python3.13/site-packages/web3/contract/contract.py", line 307, in call
    block_id = parse_block_identifier(self.w3, block_identifier)
  File "/Users/f4ever/Library/Caches/pypoetry/virtualenvs/py3.13/lib/python3.13/site-packages/web3/_utils/contracts.py", line 337, in parse_block_identifier
    raise BlockNumberOutOfRange
web3.exceptions.BlockNumberOutOfRange

At the moment, to implement support for passing block hashes to contract calls, I have to write a fairly large chunk of workaround code, which would break with each Web3.py update. I propose not necessarily implement my exact approach, but at least provide a cleaner way to bypass the current limitation.

@fselmo
Copy link
Collaborator

fselmo commented Mar 24, 2025

Hmm, that's fair. I was not aware that blockhash was widely accepted for eth_call across clients. I think it's worth exploring a try / except here to pass through the blockhash directly at first, otherwise revert to the current setup. I'll reopen this.


edit: Also, TIL, it is already part of the official spec (this was not the case before) so I think we can definitely just default to this in the next major version as well, since it would be breaking to introduce it now.

@fselmo fselmo reopened this Mar 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants