ethpandaops / dora

Dora the Explorer is a lightweight slot explorer for the ethereum beaconchain
https://beaconlight.ephemery.dev/
GNU General Public License v3.0
83 stars 26 forks source link

fix panic when loading validator activity from cached voting aggregation #181

Closed pk910 closed 3 days ago

pk910 commented 4 days ago

reported by barnabas:

URL: /validators/activity?group=3&c=50
Time: 2024-11-27 13:45:45.245965314 +0000 UTC m=+41915.060260465
Version: git-7909de3

Error:
page call 84322 panic: runtime error: invalid memory address or nil pointer dereference

Stack Trace:
goroutine 1597759 [running]:
runtime/debug.Stack()
    /opt/hostedtoolcache/go/1.22.9/x64/src/runtime/debug/stack.go:24 +0x5e
github.com/ethpandaops/dora/services.(*FrontendCacheService).processPageCall.func1.1()
    /home/runner/work/dora/dora/services/frontendcache.go:131 +0xd4
panic({0x1349200?, 0x357ce40?})
    /opt/hostedtoolcache/go/1.22.9/x64/src/runtime/panic.go:770 +0x132
github.com/ethpandaops/dora/services.(*ChainService).GetValidatorActivity(0xc0000ac540, 0x4, 0x1)
    /home/runner/work/dora/dora/services/chainservice.go:373 +0x1a3
github.com/ethpandaops/dora/handlers.buildValidatorsActivityPageData(0x0, 0x32, {0x14c17ea, 0x5}, 0x3)
    /home/runner/work/dora/dora/handlers/validators_activity.go:118 +0x3cb
github.com/ethpandaops/dora/handlers.getValidatorsActivityPageData.func1(0xc00021c1b0?)
    /home/runner/work/dora/dora/handlers/validators_activity.go:80 +0x38
github.com/ethpandaops/dora/services.(*FrontendCacheService).processPageCall.func1(0xc00a80dd40?)
    /home/runner/work/dora/dora/services/frontendcache.go:148 +0x1f0
created by github.com/ethpandaops/dora/services.(*FrontendCacheService).processPageCall in goroutine 1561427
    /home/runner/work/dora/dora/services/frontendcache.go:125 +0x347

The stack trace indicates a nil pointer access in here chainservice.go:373. The only possible nil pointer in this line is the ActivityBitfield field within the voting aggregation. However, this field should not be nil as I'm checking for all prerequisites to get this value before requesting the aggregation chainservice.go:365.

The only way how the field can still be uninitialized in this situation is if the voting aggregation was done without proper values earlier and we got that cached aggregation. This seems to be possible when the voting aggregation was first triggered even before the async duty pre-calculation finished (which can take a second or two with larget validator sets). This PR fixes the voting aggregation cache to avoid serving incomplete aggregations when precalculated duties are available.