core/filtermaps: fixed indexer checkpoint initialization (#31419)

This PR fixes a bug in the `lastMapBoundaryBefore` logic that resulted
in incorrect checkpoint initialization (started rendering from the
previous epoch boundary which caused the `needTailEpoch` check to fail).
Apparently the bug was present before but went unnoticed because
`needTailEpoch` behaved differently.
Fixes https://github.com/ethereum/go-ethereum/issues/31413
This commit is contained in:
Felföldi Zsolt 2025-03-18 13:46:23 +01:00 committed by GitHub
parent e5f4b274b3
commit fe640f8f57
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 19 additions and 13 deletions

View file

@ -346,6 +346,9 @@ func (f *FilterMaps) needTailEpoch(epoch uint32) bool {
if epoch > firstEpoch {
return true
}
if (epoch+1)<<f.logMapsPerEpoch >= f.indexedRange.maps.AfterLast() {
return true
}
if epoch+1 < firstEpoch {
return false
}

View file

@ -185,27 +185,30 @@ func (f *FilterMaps) lastCanonicalMapBoundaryBefore(renderBefore uint32) (nextMa
// lastMapBoundaryBefore returns the latest map boundary before the specified
// map index.
func (f *FilterMaps) lastMapBoundaryBefore(mapIndex uint32) (uint32, bool) {
if !f.indexedRange.initialized || f.indexedRange.maps.AfterLast() == 0 {
func (f *FilterMaps) lastMapBoundaryBefore(renderBefore uint32) (uint32, bool) {
if !f.indexedRange.initialized || f.indexedRange.maps.AfterLast() == 0 || renderBefore == 0 {
return 0, false
}
if mapIndex > f.indexedRange.maps.AfterLast() {
mapIndex = f.indexedRange.maps.AfterLast()
afterLastFullMap := f.indexedRange.maps.AfterLast()
if afterLastFullMap > 0 && f.indexedRange.headIndexed {
afterLastFullMap-- // last map is not full
}
if mapIndex > f.indexedRange.maps.First() {
return mapIndex - 1, true
firstRendered := min(renderBefore-1, afterLastFullMap)
if firstRendered == 0 {
return 0, false
}
if mapIndex+f.mapsPerEpoch > f.indexedRange.maps.First() {
if mapIndex > f.indexedRange.maps.First()-f.mapsPerEpoch+f.indexedRange.tailPartialEpoch {
mapIndex = f.indexedRange.maps.First() - f.mapsPerEpoch + f.indexedRange.tailPartialEpoch
}
if firstRendered >= f.indexedRange.maps.First() {
return firstRendered - 1, true
}
if firstRendered+f.mapsPerEpoch > f.indexedRange.maps.First() {
firstRendered = min(firstRendered, f.indexedRange.maps.First()-f.mapsPerEpoch+f.indexedRange.tailPartialEpoch)
} else {
mapIndex = (mapIndex >> f.logMapsPerEpoch) << f.logMapsPerEpoch
firstRendered = (firstRendered >> f.logMapsPerEpoch) << f.logMapsPerEpoch
}
if mapIndex == 0 {
if firstRendered == 0 {
return 0, false
}
return mapIndex - 1, true
return firstRendered - 1, true
}
// emptyFilterMap returns an empty filter map.