Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

Listening for Future Events #1504

Closed
hyndsite opened this issue Apr 24, 2021 · 5 comments
Closed

Listening for Future Events #1504

hyndsite opened this issue Apr 24, 2021 · 5 comments

Comments

@hyndsite
Copy link

The closed issue here talks about how to obtain future events as @mrwillis previous example of getting only future events, does produce events from the past as well.

//provides events at least as far back as current block (which is not future)
const filter = contract.filters.MyEmittedEvent(arg1, arg2);
contract.on(filter, callback);

@ricmoo has pointed out a poll approach using queryFilter, but if we want to subscribe to events, and only get for future events, I don't see there is way to do that with contract.on() - is that correct? queryFilter is only going to allow for a polling approach as opposed to being notified on an emitted Solidity event.

The only way I have found for this to work, is to get the current block number getBlockNumber and check on every fired event that I am subscribed to contract.on(filter, callback)) and react to only block number above the current block number.

@hyndsite hyndsite added the investigate Under investigation and may be a bug. label Apr 24, 2021
@zemse
Copy link
Collaborator

zemse commented Apr 24, 2021

previous example of getting only future events does produce events from the past as well.

Do you mean the past events from the current block (the last mined block)?

The pooling mechanism in ethers.js considers block numbers up to currentBlockNumber - 1 as past (code reference), and hence when you create a listener using contract.on, you even get the events emitted in the current block.

This is generally not a problem when you have a chain continuously mining blocks in a short interval. But if you have a chain with a large block time or an environment like ganache, which mines a block only when a tx is received. To handle these situations, the logic you described is fine.

const startBlockNumber = await provider.getBlockNumber();

contract.on(filter, (...args) => {
  const event = args[args.length - 1];
  if(event.blockNumber <= startBlockNumber) return; // do not react to this event
  
  // further logic
})

@navneetgulati
Copy link

So shouldn't it consider currentBlockNumber as the past block too since if eventListener is attached on it, it is obvious that the eventListener will be looking for events in the next block? Or we should provide some string like "latest"(as is the case with Web3js) where it only listens to Future Events?

@zemse
Copy link
Collaborator

zemse commented Apr 26, 2021

Actually "latest" means last block mined as in eth wiki ref.

Though I understand what you mean. But I think it depends on what you consider a confirmed block. All the blocks behind your confirmation block are in the past, while anything next to it is in the future. If you don't consider any confirmations, then it can be valid to consider the current block as past (in the case of PoA chains, or Ganache). In ethereum mainnet, most of the forked blocks have a depth of 1. So you can fairly say the block behind the current block is in the past but the current block is not necessarily past yet.

@ricmoo
Copy link
Member

ricmoo commented Apr 27, 2021

Yes, ethers considers the current block as part of "from now on". Often you want your process that is mining information to start with events from the current block. There are many use cases for the event emitter, and if the event listener is registered outside the context of a transaction, there is no distinction between starting at the current block or next block. And if you submit a transactions, that certainly won't be part of the current block, so in those cases it is handled implicitly.

You can either add a guard in your event handler (like your above example), or something like this might work for your purposes too:

provider.once("block", () => {
    provider.on(filter, (...args) => { ... });
});

Does that make sense?

@ricmoo
Copy link
Member

ricmoo commented Apr 27, 2021

(moving to discussions)

@ricmoo ricmoo closed this as completed Apr 27, 2021
@ethers-io ethers-io locked and limited conversation to collaborators Apr 27, 2021
@ricmoo ricmoo removed the investigate Under investigation and may be a bug. label Oct 20, 2021

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants