ethereum / web3.py

A python interface for interacting with the Ethereum blockchain and ecosystem.
http://web3py.readthedocs.io
MIT License
5.04k stars 1.71k forks source link

Add API to parse event data from generic filter #1097

Open carver opened 6 years ago

carver commented 6 years ago

What was wrong?

@theanht1 Hi guys, are there any ways to filter all events of a contract in a human readable way like contract.allEvents of web3js ? @carver not currently. Last we talked about it, the complexity of handling different events in response didn't seem worth the ease of setting up a single listener for all events. Better to set up a filter for each event you care about, and handle them distinctly. @theanht1 I want to handle events in the order of their created time, is multiple filters work in this case?

There isn't a great solution for this right now.

How can it be fixed?

Maybe something like:

my_contract = w3.eth.contract(...)
event_filter = web3.eth.filter({'address': my_contract.address})
for event_log in event_filter.get_all_events():
  try:
    parsed_event = my_contract.parse_unknown_event(event_log)  # new API
  except ValidationError:
    # this is raised if the topic in event_log doesn't match any of events in the ABI
    raise ValueError(f"{event_log} from {my_contract.address} filter not in {my_contract.events}")
  else:
      handle_parsed_event(parsed_event)

def handle_parsed_event():
  # application-specific logic here

This is just a first stab at an API. I thought about putting it under my_contract.events.parse_unknown(), but then it would conflict with an event named parse_unknown.

koirikivi commented 6 years ago

We already have an API that works like this:

my_contract.events.MyEvent().createFilter(...)

While I think the my_contract.parse_unknown_event would probably be a good addition, it looks a bit cumbersome compared to the above API. Wouldn't something like this be better:

my_contract.create_event_filter(...)

Another possibility would be to have a helper function that could take N number of events as arguments. Maybe something like this:

create_event_filter(
    events=[my_contract.events.MyEvent(), my_contract.events.AnotherEvent()],
    fromBlock=123,
    ...
)

or

compose_events(
    my_contract.events.MyEvent(),
    my_contract.events.AnotherEvent()
).createFilter(...)

Just my thoughts :) .

pipermerriam commented 6 years ago

I think I think the idea of working with Event objects most.

event_a = c.events.EventA()
event_b = c.events.EventB()

event_ab = event_a | event_b
event_ab.create_filter()

Easy to accomplish by overloading the binary | operator on our event object.