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

When re-creating listeners in EVMConnect/EthConnect/FabConnect use the last event block #1534

Merged
merged 3 commits into from
Jul 10, 2024

Conversation

peterbroadhurst
Copy link
Contributor

@peterbroadhurst peterbroadhurst commented Jun 24, 2024

See #1531

Every time Core starts, it confirms all the listeners exist that it needs for all of:

This is needed for two cases:

  1. In case the listeners were deleted operationally for any reason (intentionally or otherwise) - such as a DR scenario
  2. In the v1.2->v1.3 migration, where we intentionally orphan all the core-wide listeners in favor of namespace-specific ones

In both of these cases, the logic was naive for the newest/latest case - where it treats "now" as the latest event.

That is a problem, as it might be a long time since the original listener was created, and it might have delivered many events already. In which case there might be "gaps" we skip over between the last event detected by the old listener, and the first event we detect on the new one.

This PR closes that window, by looking at the protocolId of the last event - which is architecturally required to be a lexicographically sorted string identifying the position of the event on the blockchain.

If there's been a previous event, that's used by the blockchain connector as the fromBlock for the new listener.

Also, if "oldest" or an explicit block number is used, and the block number is before the block determined by the above process, then the newer block is used.

// is passed through, and the listener does not exist.
fb := database.BlockchainEventQueryFactory.NewFilter(ctx).Sort("-protocolid").Limit(1)
latestEvents, _, err := mm.database.GetBlockchainEvents(ctx, mm.namespace.Name, fb.Eq(
"listener", nil,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we not using the multiparty listener ID here? We don't have access to it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Specifically the thing that distinguishes the blockchainevents for the multi-party BatchPin events, is the lack of a listener reference (there isn't one in the FF model for the BatchPin case).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah makes sense

@peterbroadhurst
Copy link
Contributor Author

PR has been updated based on the conversation here, so that in the case a specific block number is supplied the recreated listener will still restart on the block before the last event (if that's after the specified block): #1531 (comment)

@EnriqueL8
Copy link
Contributor

Will be testing this one today e2e

Copy link
Contributor

@EnriqueL8 EnriqueL8 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewing I thought about a crazy edge case... The protocol ID is block number/transaction number /event number so if we recreate a listener with block number of the last protocol ID but we haven't consumed all the events from that block could we lose those events? Is it safer to go one down of the procotol id or am I over complicating this? Would have to see how FireFly acknowledges events from FFTM and maybe the assumption you have made is that you get all the events per block in the webscoket?

@EnriqueL8 EnriqueL8 added this to the v1.3.1 milestone Jul 3, 2024
@EnriqueL8
Copy link
Contributor

@EnriqueL8
Copy link
Contributor

Have tested this one E2E by doing the following experiment:

  • Setup a 1.3.0 FF stack
  • Deploy a contract and a listener with the option to listen from newest
  • Delete the listener from EVMConnect
  • Restart the FF with the code from this PR
  • Find the new listener created in EVMConnect and make sure the fromBlock matches the last protocol ID for the last event - 1

Copy link
Contributor

@EnriqueL8 EnriqueL8 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me!

@peterbroadhurst
Copy link
Contributor Author

we recreate a listener with block number of the last protocol ID but we haven't consumed all the events from that block could we lose those events? Is it safer to go one down of the procotol id or am I over complicating this?

This is the reason we go one block back:

// We jump back on block from the last event, to minimize re-delivery while ensuring
// we get all events since the last delivered (including subsequent events in the same block)
parsedUint--

@EnriqueL8
Copy link
Contributor

Yeah I realised with #1534 (comment)

@EnriqueL8 EnriqueL8 merged commit c00ecf8 into main Jul 10, 2024
14 checks passed
@EnriqueL8 EnriqueL8 mentioned this pull request Jul 11, 2024
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

Successfully merging this pull request may close these issues.

2 participants