Skip to content

core/filtermaps: fix log index initialization #31750

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

Merged
merged 3 commits into from
May 3, 2025

Conversation

zsfelfoldi
Copy link
Contributor

This PR fixes an initialization bug that in some cases caused the map renderer to leave the last, partially rendered map as is and resume rendering from the next map. At initialization we check whether the existing rendered maps are consistent with the current chain view and revert them if necessary. Until now this happened through an ugly hacky solution, a "limited" chain view that was supposed to trigger a rollback of some maps in the renderer logic if necessary. This whole setup worked under assumptions that just weren't true any more. As a result it always tried to revert the last map but also it did not shorten the indexed range, only set headIndexed to false which indicated to the renderer logic that the last map is fully populated (which it wasn't).
Now an explicit rollback of any unusable (reorged) maps happens at startup, which also means that no hacky chain view is necessary, as soon as the new FilterMaps is returned, the indexed range and view are consistent with each other.

In the first commit an extra check is also added to writeFinishedMaps so that if there is ever again a bug that would result in a gapped index then it will not break the db with writing the incomplete data. Instead it will return an indexing error which causes the indexer to revert to unindexed mode and print an error log instantly. Hopefully this will not ever happen in the future, but in order to test this safeguard check I manually triggered the bug with only the first commit enabled, which caused an indexing error as expected. With the second commit added (the actual fix) the same operation succeeded without any issues.

Note that the database version is also bumped in this PR in order to enforce a full reindexing as any existing database might be potentially broken.

Fixes #31729

@zsfelfoldi zsfelfoldi requested a review from rjl493456442 as a code owner May 1, 2025 06:35
@zsfelfoldi zsfelfoldi added this to the 1.15.11 milestone May 1, 2025
@rjl493456442
Copy link
Member

rjl493456442 commented May 2, 2025

This PR fixes an initialization bug that in some cases caused the map renderer to leave the last, partially rendered map as is and resume rendering from the next map.

Can you please elaborate in which case, this bug can occur?

This whole setup worked under assumptions that just weren't true any more. As a result it always tried to revert the last map but also it did not shorten the indexed range, only set headIndexed to false which indicated to the renderer logic that the last map is fully populated (which it wasn't).

I can see the indexed range is not shortened, but I don't understand why setting headIndexed to false will indicate the last map is fully populated?

@zsfelfoldi
Copy link
Contributor Author

Can you please elaborate in which case, this bug can occur?

If the database was in a head indexed state at last shutdown then 'initChainView' unnecessarily rolled back the last partially populated map and returned a limited chain view. This caused the initializer to set 'headIndexed' to false but did not shorten the range. Now if the first rendering after init just replaced the head map then it fixed itself. This happened if the chain import did not start for a while and the indexer just re-rendered the head map with the old head.
But if the chain import started earlier than the head rendering and imported a number of blocks that already crossed the map boundary then the renderer was initialized at the incorrect map boundary (the end of the partially filled map). In practice it initialized the iterator at the last block, then iterated it until the actual boundary, passing through a few blocks without actually rendering them. The next map was rendered correctly but the partial one remained untouched.

I can see the indexed range is not shortened, but I don't understand why setting headIndexed to false will indicate the last map is fully populated?

Because maps are always rendered either until map boundary or chain head. So if the head is reached then the last map is probably partial, otherwise full.

}
newRange.blocks.SetAfterLast(lastBlockNumber) // lastBlockNumber is probably partially indexed
Copy link
Member

@rjl493456442 rjl493456442 May 3, 2025

Choose a reason for hiding this comment

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

This status is very weird.

  • Let's say the current indexed map is [0, 100] and headIndexed = true; the last block of map 100 is 10000;
  • However, the block 10000 beyonds the new indexedView (reorg);
  • The map 100 is reverted;
  • The indexedRange is converted to [0, 99];
  • The last block of map 99 is 9900;
  • The block 9900 is partially indexed in map 99 (it crosses the map 99 and 100);
  • The indexedRange is converted to map: [0, 99], blocks [0, 9899], headIndexed = false;

This status is very weird; the if the map is full, it's usually written with headIndexed = false; If the map is not full but all blocks have been indexed, then the headIndexed = true;

The initialized status of indexedRange is actually an invalid one (the last block is not the real one corresponds to the map)

Copy link
Member

Choose a reason for hiding this comment

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

EDIT, never mind.

It's correct.

@zsfelfoldi zsfelfoldi merged commit 8868ad6 into ethereum:master May 3, 2025
3 of 4 checks passed
0g-wh pushed a commit to 0g-wh/0g-geth that referenced this pull request May 8, 2025
This PR fixes an initialization bug that in some cases caused the map
renderer to leave the last, partially rendered map as is and resume
rendering from the next map. At initialization we check whether the
existing rendered maps are consistent with the current chain view and
revert them if necessary. Until now this happened through an ugly hacky
solution, a "limited" chain view that was supposed to trigger a rollback
of some maps in the renderer logic if necessary. This whole setup worked
under assumptions that just weren't true any more. As a result it always
tried to revert the last map but also it did not shorten the indexed
range, only set `headIndexed` to false which indicated to the renderer
logic that the last map is fully populated (which it wasn't).
Now an explicit rollback of any unusable (reorged) maps happens at
startup, which also means that no hacky chain view is necessary, as soon
as the new `FilterMaps` is returned, the indexed range and view are
consistent with each other.

In the first commit an extra check is also added to `writeFinishedMaps`
so that if there is ever again a bug that would result in a gapped index
then it will not break the db with writing the incomplete data. Instead
it will return an indexing error which causes the indexer to revert to
unindexed mode and print an error log instantly. Hopefully this will not
ever happen in the future, but in order to test this safeguard check I
manually triggered the bug with only the first commit enabled, which
caused an indexing error as expected. With the second commit added (the
actual fix) the same operation succeeded without any issues.

Note that the database version is also bumped in this PR in order to
enforce a full reindexing as any existing database might be potentially
broken.

Fixes ethereum#31729
queenybee39 added a commit to queenybee39/go-ethereum that referenced this pull request May 16, 2025
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.

failed to process log index epoch 270: failed to retrieve log at index 18122937602
3 participants