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

Get past events #37

Closed
gazambuja opened this issue Oct 5, 2017 · 19 comments

Comments

@ricmoo

This comment has been minimized.

Copy link
Member

commented Oct 6, 2017

Heya!

I do need to add this to the documentation...

You can use the following to achieve this:

provider.resetEventsBlock(0)

which will begin processing all events from block 0 forward. Keep in mind, that INFURA nodes may not provider the entire history, and even a local node may have issues with this. There isn't currently a great solution to the performance issue, but the Geth team is working on improving this.

You can specify any block number, so if you know the block you are interested in, that might improve its reliability as well. Certainly, there is no need to look at contract events before the contract's deployment, for example. And if you keep a local cache, you have an idea where to start from.

@GFJHogue

This comment has been minimized.

Copy link

commented Oct 18, 2017

Hey @ricmoo!

If were to use provider.resetEventsBlock(fromBlock) to run Contract event callbacks starting at fromBlock, would calling provider.getBlockNumber() in the event callback return the correct block numbers?

@ricmoo

This comment has been minimized.

Copy link
Member

commented Oct 18, 2017

The provider.getBlockNumber() will hit the Ethereum node for the current block, so yes the correct block number will be returned; it doesn't use the internally cached lastBlockNumber.

It will regenerate all events though, including block, address (balance changed) and transaction (mined) events. For transaction events, you should generally use provider.once instead of provider.on, since they are usually only mined once.

I do need to figure out a cleaner interface. If you need more fine grained control, you can use the Interface from your Contract. If you , for example, had a function called someEvent(address), your contract.interface.events.someevent is an object that can parse the results from provider.getLogs. This is more advanced, so let me know if you need more specifics for this method.

I will mull over other options (and feel free to suggest some) for how they API could handle this.

@ricmoo ricmoo added the discussion label Oct 21, 2017

@jeansoon

This comment has been minimized.

Copy link

commented Jun 7, 2018

Hey @ricmoo,

If I pass BigNumber into provider.resetEventsBlock(fromBlock), when the function doPoll() happened, it will not add the BigNumber correct lastBlockNumber + 1 inside the for loop. The result will be treat it as string to append "1".

@ricmoo

This comment has been minimized.

Copy link
Member

commented Jun 7, 2018

Block numbers should be specified as normal JavaScript numbers.

They support going to the year 4,284,246,220... Give or take. :)

But I should add more checks to make sure variable types are passed in correctly. This will be coming with the TypeScript migration; much tighter variable type checking.

@cemozerr

This comment has been minimized.

Copy link

commented Oct 24, 2018

Hey @ricmoo,

If you , for example, had a function called someEvent(address), your contract.interface.events.someevent is an object that can parse the results from provider.getLogs. This is more advanced, so let me know if you need more specifics for this method.

I'm trying to figure out how contract.interface.events.someevent object could help me parse the results from provider.getLogs, however, I'm stuck. How do you suggest approaching that?

@ricmoo

This comment has been minimized.

Copy link
Member

commented Oct 25, 2018

There is also a contract.interface.parseLog(log) function, which will help identify all the things you care about, which may be easier... Just pass in the log entry. :)

Otherwise, the contract.interface.events,someEvent.decode(data, topics) is what you will likely need. But I recommend trying out the parseLog first.

@cemozerr

This comment has been minimized.

Copy link

commented Oct 25, 2018

Thanks @ricmoo ! parseLog was very helpful.

@ricmoo

This comment has been minimized.

Copy link
Member

commented Jan 23, 2019

I think the resetEventsBlock and new contract.filter.eventName has solved this for most people. If not, please feel free to re-open this issue.

Thanks! :)

@ricmoo ricmoo closed this Jan 23, 2019

@kfichter

This comment has been minimized.

Copy link

commented Mar 1, 2019

I have a specific use-case where I'm trying to query multiple past events simultaneously. Running provider.resetEventsBlock(0) doesn't really work because you get a race condition where the check for one event will reset the provider, but the check for another event will reset the provider again. If things go wrong then you end up missing events.

Currently I'm handling this by creating a new provider for each event, but that doesn't seem particularly scalable. Any suggestions on handling this?

Also doesn't seem like this plays particularly nicely with getting events between two specific blocks. Client might get a ton of more recent events and have to filter them out manually instead of just getting the events for specific blocks.

@FrozenKiwi

This comment has been minimized.

Copy link

commented Mar 2, 2019

@kfichter - maybe check out the recipe for using etherscan to get all transactions for an address:

https://docs.ethers.io/ethers.js/html/cookbook-accounts.html#get-transaction-history

You will likely need to do your filtering yourself, but it should avoid the race condition

@k06a

This comment has been minimized.

Copy link

commented Jun 22, 2019

How is it possible to fetch all events by signature for all possible smart contract addresses?

@k06a

This comment has been minimized.

Copy link

commented Jun 22, 2019

@ricmoo

This comment has been minimized.

Copy link
Member

commented Jun 22, 2019

Quick note: If you want all possible smart contract addresses, you can simply omit the address and just include the topics. The array of addresses is only necessary to filter based on those addresses. :)

@jtakalai

This comment has been minimized.

Copy link

commented Jun 25, 2019

Would be great if resetEventsBlock would return a promise that resolves once it's done getting past events and calling the callbacks; maybe also if the callbacks return a promise, then waiting on those promises before resolving. Now it seems it's not knowable to the caller of resetEventsBlock when the "playback" completes, although internally the function would query the past events, then resume polling, right?

@jtakalai

This comment has been minimized.

Copy link

commented Jun 25, 2019

To answer @gazambuja the original poster, there's also provider.getLogs documented in https://docs.ethers.io/ethers.js/html/api-providers.html#contract-state

Downside is, you need to do the log parsing yourself with parseLogs documented in https://docs.ethers.io/ethers.js/html/api-advanced.html#parsing-objects (as explained above :)

@ricmoo

This comment has been minimized.

Copy link
Member

commented Jul 9, 2019

Also, if you use v5, you can use contract.queryFilter(filter [ , fromBlock [ , toBlock ] ] ), which will include the parsed events. :)

JaegarSarauer added a commit to Cajarty/PixelRealEstate that referenced this issue Aug 14, 2019
@jtakalai

This comment has been minimized.

Copy link

commented Sep 20, 2019

Still using v4, so this may or may not apply to v5.

An odd thing in Contract.parseLog (for querying) and Contract.on (for listening) is differences in naming:

Details, but it would be nice to have consistency in how the events look.

(EDIT: I agree that event.event just looks stupid, and event.name looks good, but ofc the question is if changing event member names at .on is a good idea (no, breaks compatibility), or if adding a redundant .name == .event is less bad... maybe adding a redundant .event == .name to parseLogs would be less bad, since parseLogs is a helper)

@jtakalai

This comment has been minimized.

Copy link

commented Sep 20, 2019

And as an answer to "If anonymous, and the only method, and the input count matches, should we parse and return it?", YES, I think in this kind of edge cases it might even be better to err on the magic side, if the alternative is just to silently go ¯\_(ツ)_/¯ (ofc I'm not a proponent of silent type coercion or similar that should flag an error :)

EDIT: Obviously it's a tradeoff of what kind of "why doesn't this work" questions you'll have to answer then :D and since I'm not the answering the questions, I'm also not calling the shots...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
9 participants
You can’t perform that action at this time.