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

Stateless contract log fetcher (for Infura) #1177

Closed
miohtama opened this issue Dec 29, 2018 · 7 comments
Closed

Stateless contract log fetcher (for Infura) #1177

miohtama opened this issue Dec 29, 2018 · 7 comments

Comments

@miohtama
Copy link
Contributor

  • Version: 4.8.2

What was wrong?

  • I could not find a convenience method on the contract to get event logs over Infura. Looks like there is only createFilter method that requires a stateful node (eth_createFilter API).

How can it be fixed?

I have sketched a web3.contract.ContractEvent function that is compatible with Infura and other stateless nodes. It is copy-paste job from createFilter

I need guidance on

  • What are the input parameters createFilter uses, so I can properly document them out (argument_files, address, topics)

  • If there is any conflicting work or feedback on the implementation

After this happy to open a PR.

def getLogs(self,
    argument_filters=None,
    fromBlock=None,
    toBlock="latest",
    address=None,
    topics=None):
    """Get events using eth_getLogs API.

    This is a stateless method, as opposite to createFilter.
    It can be safely called against nodes which do not provide eth_newFilter API, like Infura.

    :param argument_filters:
    :param fromBlock:
    :param toBlock:
    :param address:
    :param topics:
    :return:
    """

    if fromBlock is None:
        raise TypeError("Missing mandatory keyword argument to getLogs: fromBlock")

    abi = self._get_event_abi()

    argument_filters = dict()

    _filters = dict(**argument_filters)

    # Construct JSON-RPC raw filter presentation based on human readable Python descriptions
    # Namely, convert event names to their keccak signatures
    data_filter_set, event_filter_params = construct_event_filter_params(
        abi,
        contract_address=self.address,
        argument_filters=_filters,
        fromBlock=fromBlock,
        toBlock=toBlock,
        address=address,
        topics=topics,
    )

    # Call JSON-RPC API
    logs = self.web3.eth.getLogs(event_filter_params)

    # Convert raw binary data to Python proxy objects as described by ABI
    for entry in logs:
        yield get_event_data(abi, entry)
@pipermerriam
Copy link
Member

I can get onboard with this. Implementation looks reasonable with potential exceptions related to topics and address (see below)

As for the parameters you should be able to infer them from the other filter creation APIs.

Allowing topics to be provided could be confusing or problematic since each event has it's own topic and combining those with user provided topics is likely to be hard to reason about.

Allowing address to be provided is also likely to result in confusion since contract instances have an address and it needs to be clearly defined whether the user can override this or what the behavior is.

In general 👍

@miohtama
Copy link
Contributor Author

miohtama commented Jan 7, 2019

Ok, let me work with a draft implementation and open it as work-in-progress PR.

Any sample tests you would recommend to duplicate against this implementation?

@dylanjw
Copy link
Contributor

dylanjw commented Jan 7, 2019

Worth mentioning web3.py provides a stateless log api with the optional local_filter_middleware. There is a short example in the doc: https://web3py.readthedocs.io/en/latest/middleware.html#locally-managed-log-and-block-filters

It uses getLogs to mimic the node filter api.

@pipermerriam
Copy link
Member

@miohtama 👍 to what @dylanjw pointed out in case it helps your use case, though I do believe that the API proposed by @miohtama still makes sense. The user-story for fetching specific logs for a specific contract address in a rich format is still kind of mediocre.

@miohtama
Copy link
Contributor Author

miohtama commented Jan 8, 2019

@dylanjw I did not know it existed. I was scratching my head why a relative simple use case is overlooked.

It is a minor addition to Contract API and that is where people will look for it, so I'll put it there with the reference to the middleware. The middleware solution may cater some use cases better.

@carver
Copy link
Collaborator

carver commented Jan 10, 2019

As an aside, I seem to recall that Infura does allow you to create/query stateful filters if you use the websocket provider.

@kclowes
Copy link
Collaborator

kclowes commented Nov 14, 2019

Looks like this was merged long ago. Closing!

@kclowes kclowes closed this as completed Nov 14, 2019
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

5 participants