1

I have a Dapp which subscribes to events using web3. I'm wondering how I can detect that the longest chain has changed or rather how I can make sure the events that I've received are canonical. The could should also work correctly for hardforks and with both getPastEvents() and subscribing to new events.

During my research, I've found this question: Is it possible to get duplicates of the log events on Ethereum when we have a fork of the chain?. The answer suggests a status field. There is a status in the receipt but that's only a boolean. Also, there is no status in the results of getPastEvents() - what happens when the fork happens while getPastEvents() receives events?

I'm not sure how web3 makes sure that events are canonical in the current implementation. In tests with Geth, the event became visible in the Dapp after about 10 seconds which suggests that it just takes the latest block into account and doesn't wait for the usual 6 or 12 blocks for the chain to become canonical.

0

There are multiple ways to address this using web3 - one using a subscription and the other using getPastEvents() on a contract.

Subscription

The first - if you want to setup a subscription to receive events on an on-going basis, you can setup a subscription that includes on("changed").

on("changed") returns Object: Fires on each log which was removed from the blockchain. The log will have the additional property "removed: true".

If a log is removed, it means it was part of a block that was uncled.

Upon receiving an event, you can tentatively store it, but also set up a subscription to block headers. Once the appropriate number of blocks have been published, and if you have not received a "changed" event - you can accept this event and kill the block header listener.

subscription documentation

Get Past Events

If you will be calling the function at multiple instances / points in time, you could also use myContract.getPastEvents(event[, options][, callback]) where you set the fromBlock and toBlock parameters in the options. For this you would set the toBlock to the result of web3.eth.getBlockNumber() minus the number of blocks you think the chain needs to "settle".`

getPastEvents documentation

getBlockNumber documentation

4
  • So one option is to poll using x = getLastBlock() - 10; getPastEvents(... { toBlock: x }, correct? I'm trying to build a status variable which gives me the "last value of an event". With subscriptions, I see only calling getPastEvents() as above every time I get a block with removed: true. Also correct? I assume that web3 doesn't send me first all the remove: true events and then publishes the old events again (which are now "valid" once more). Jan 27 '20 at 13:30
  • For the sake of argument, assume that I store an uint value from the event and I need to know the last "valid" / correct / canonical value at all times. Jan 27 '20 at 13:31
  • To be honest, I don't totally follow your comments here. Something you could potentially do is set up your event subscription - upon receiving an event - tentatively store it, but also set up a subscription to block headers. Once the appropriate number of blocks have been published, and if you have not received a "changed" event - you can accept this event and kill the block header listener.
    – Steven V
    Jan 27 '20 at 13:56
  • 1
    Thanks, to trigger on a "block received" event feels like a simple, stable, understandable solution. Can you add that to your answer plus see my edit, please. Jan 27 '20 at 14:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.