koinos / koinos-p2p

The p2p microservice orchestrates the distribution of blocks and transactions between peers.
MIT License
6 stars 4 forks source link

[BUG]: Suspect processing in BlockApplicator.handleForkHeads() #233

Closed theoreticalbts closed 2 years ago

theoreticalbts commented 2 years ago

Is there an existing issue for this?

Current behavior

AFAIK it works like this:

When LIB advances, BlockApplicator invalidates pending blocks on minority forks that forked behind LIB.

Current behavior implemented in handleForkHeads() seems to be as follows:

Expected behavior

I would expect the following behavior:

Steps to reproduce

During normal sync, spam of p2perrors.ErrUnknownPreviousBlock (previous block does not exist) occurs.

Environment

- OS: Ubuntu 22.04

Anything else?

Here's a more detailed analysis of this problem:

The invariant means we know the pending blocks' starting height (it's the LIB root), and there are no gaps in height, so the currently implemented, general height handling logic is unnecessary and inefficient; we can just use a for loop:

The current code doesn't consider that some blocks ahead of LIB (in terms of height) are no longer reachable after an LIB update. We can find all such blocks by querying for blocks with same height as LIB, then following them forward in the graph:

With respect to naughty points:

There may be some misbehavior cases where currently BlockApplicator errors result in correct assignment of naughty points to peers. For these cases, I suggest moving the detection logic to the peer handler.

(As a matter of project management, I suggest accepting a PR for this issue even if it disables / deletes correct detection of some genuine misbehaviors. Then have a separate, separately prioritized issue / PR to re-implement detection of those misbehaviors in the peer handler.)

I'm fairly sure the above-mentioned tree trimming logic is far from original, and it already exists (with unit tests!) somewhere in chain or statedb. The most productive way to handle this issue may be to simply re-implement that implementation in Go.