Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
030ef34
Add Gloas fork support
qu0b Jan 2, 2026
c7d9d65
Fix wsl lint issue
qu0b Jan 2, 2026
bb1ae65
Fix golangci-lint issues
qu0b Jan 2, 2026
5e97e87
update dependency & go lint fixes
qu0b Jan 2, 2026
5eb8c84
update the go-eth2-client dependency
qu0b Jan 2, 2026
f979d4d
update dependency
qu0b Jan 2, 2026
d9838ff
fix timestamp
qu0b Jan 2, 2026
9e7d2a5
fix version
qu0b Jan 2, 2026
be867b7
remove gloas check update go-eth2-client
qu0b Jan 12, 2026
2d562dd
update go-eth2-client to qu0b/eip7928 with SlotNumber (EIP-7843) support
qu0b Feb 11, 2026
0cf2718
switch go-eth2-client dependency back to pk910 (SlotNumber merged)
qu0b Feb 11, 2026
94f5b2f
chore: bump gloas support dependencies
samcm Mar 6, 2026
7a92f3f
Update go-eth2-client for consensus-specs alpha.4
barnabasbusa Mar 31, 2026
e6d8361
Merge pull request #235 from ethpandaops/bbusa/alpha4
barnabasbusa Mar 31, 2026
6710869
Fix linting issues
barnabasbusa Mar 31, 2026
1d11499
chore: trigger new gloas release
barnabasbusa Mar 31, 2026
99dcf29
Merge master into release/gloas
barnabasbusa Mar 31, 2026
3357bb3
chore(deps): migrate go-eth2-client to ethpandaops fork v0.0.1
barnabasbusa Apr 14, 2026
2a09dcb
Merge pull request #238 from ethpandaops/chore/bump-go-eth2-client-et…
barnabasbusa Apr 17, 2026
8faf752
chore(deps): bump ethpandaops/go-eth2-client to v0.1.0
barnabasbusa Apr 21, 2026
9326d5c
Merge pull request #240 from ethpandaops/chore/bump-go-eth2-client-v0…
barnabasbusa Apr 21, 2026
a0dfdef
fix: prevent uint64 underflow in ListFinalizedSlots on short-lived ch…
barnabasbusa Apr 21, 2026
3a0d6b0
Merge pull request #242 from ethpandaops/bbusa/fix-list-finalized-slo…
barnabasbusa Apr 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ linters:
- tparallel
- unconvert
- whitespace
- wsl
- wsl_v5
settings:
errcheck:
check-type-assertions: true
Expand All @@ -39,6 +39,10 @@ linters:
nolintlint:
require-explanation: true
require-specific: true
wsl_v5:
allow-first-in-block: true
allow-whole-block: false
branch-max-lines: 2
exclusions:
generated: lax
presets:
Expand Down
1 change: 0 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ func loadConfigFromFile(file string) (*checkpointz.Config, error) {
}

yamlFile, err := os.ReadFile(file)

if err != nil {
return nil, err
}
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ module github.com/ethpandaops/checkpointz

go 1.25.1

replace github.com/attestantio/go-eth2-client => github.com/qu0b/go-eth2-client v0.0.0-20260102172406-1deaa6deedd2

require (
github.com/attestantio/go-eth2-client v0.27.2
github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9
Expand Down Expand Up @@ -79,7 +81,6 @@ require (
golang.org/x/text v0.31.0 // indirect
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
google.golang.org/protobuf v1.36.8 // indirect
gopkg.in/Knetic/govaluate.v3 v3.0.0 // indirect
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
12 changes: 2 additions & 10 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
github.com/OffchainLabs/hashtree v0.2.1-0.20250530191054-577f0b75c7f7 h1:0r1HjExe/tyypkt380UTpjvILd5kLw51Xzl6a+hknQ8=
github.com/OffchainLabs/hashtree v0.2.1-0.20250530191054-577f0b75c7f7/go.mod h1:b07+cRZs+eAR8TR57CB9TQlt5Gnl/06Xs76xt/1wq0M=
github.com/attestantio/go-eth2-client v0.27.2 h1:VjA9R39ovy8ryb7IpFfD5eLYBg/20biztxh6fKZ7/K0=
github.com/attestantio/go-eth2-client v0.27.2/go.mod h1:i56XBegxVt7wXupnLBOj9IyGwy5cqaoTsCSKlwTubEU=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/casbin/govaluate v1.8.0 h1:1dUaV/I0LFP2tcY1uNQEb6wBCbp8GMTcC/zhwQDWvZo=
Expand All @@ -26,10 +24,6 @@ github.com/emicklei/dot v1.6.4 h1:cG9ycT67d9Yw22G+mAb4XiuUz6E6H1S0zePp/5Cwe/c=
github.com/emicklei/dot v1.6.4/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s=
github.com/ethereum/go-ethereum v1.16.4 h1:H6dU0r2p/amA7cYg6zyG9Nt2JrKKH6oX2utfcqrSpkQ=
github.com/ethereum/go-ethereum v1.16.4/go.mod h1:P7551slMFbjn2zOQaKrJShZVN/d8bGxp4/I6yZVlb5w=
github.com/ethpandaops/beacon v0.65.0 h1:ssnab73uiuzhmhtU56q9D3ecVrEYv5n+tuqrXRK4YAg=
github.com/ethpandaops/beacon v0.65.0/go.mod h1:lgzrJjQVV77wZ+PJymsY3bQbAK4jrtP8n3WOwMf1Pcs=
github.com/ethpandaops/beacon v0.65.1-0.20251204024030-639105ffe6c2 h1:WU40omAqHrPF/Mfovc9+eMCrTAl8Km/KOanyYqr3SBg=
github.com/ethpandaops/beacon v0.65.1-0.20251204024030-639105ffe6c2/go.mod h1:lgzrJjQVV77wZ+PJymsY3bQbAK4jrtP8n3WOwMf1Pcs=
github.com/ethpandaops/beacon v0.66.0 h1:BRnf4yTEzkZwHW6sTp1x+mBoO5pwbQOX6wtLt3Nh1Y4=
github.com/ethpandaops/beacon v0.66.0/go.mod h1:lgzrJjQVV77wZ+PJymsY3bQbAK4jrtP8n3WOwMf1Pcs=
github.com/ethpandaops/ethwallclock v0.2.0 h1:EeFKtZ7v6TAdn/oAh0xaPujD7N4amjBxrWIByraUfLM=
Expand Down Expand Up @@ -160,8 +154,6 @@ github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9k
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/pk910/dynamic-ssz v0.0.4 h1:DT29+1055tCEPCaR4V/ez+MOKW7BzBsmjyFvBRqx0ME=
github.com/pk910/dynamic-ssz v0.0.4/go.mod h1:b6CrLaB2X7pYA+OSEEbkgXDEcRnjLOZIxZTsMuO/Y9c=
github.com/pk910/dynamic-ssz v1.1.1 h1:b8sPR8fyhBvz8SHa2RH20SNtt5VDzAEY6fKsPCUcYX4=
github.com/pk910/dynamic-ssz v1.1.1/go.mod h1:3zyemisUysY2PWACZ8LeZS2tAw8AkuTb2GaLmqYsg1I=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
Expand All @@ -181,6 +173,8 @@ github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15 h1:lC8ki
github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15/go.mod h1:8svFBIKKu31YriBG/pNizo9N0Jr9i5PQ+dFkxWg3x5k=
github.com/prysmaticlabs/gohashtree v0.0.4-beta h1:H/EbCuXPeTV3lpKeXGPpEV9gsUpkqOOVnWapUyeWro4=
github.com/prysmaticlabs/gohashtree v0.0.4-beta/go.mod h1:BFdtALS+Ffhg3lGQIHv9HDWuHS8cTvHZzrHWxwOtGOs=
github.com/qu0b/go-eth2-client v0.0.0-20260102172406-1deaa6deedd2 h1:39SAuAZOwmEnoLFjfr+o2tTmW58liWI9pLfS2+gvd7w=
github.com/qu0b/go-eth2-client v0.0.0-20260102172406-1deaa6deedd2/go.mod h1:fvULSL9WtNskkOB4i+Yyr6BKpNHXvmpGZj9969fCrfY=
github.com/r3labs/sse/v2 v2.10.0 h1:hFEkLLFY4LDifoHdiCN/LlGBAdVJYsANaLqNYa1l/v0=
github.com/r3labs/sse/v2 v2.10.0/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktEmkNJ7I=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
Expand Down Expand Up @@ -290,8 +284,6 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/Knetic/govaluate.v3 v3.0.0 h1:18mUyIt4ZlRlFZAAfVetz4/rzlJs9yhN+U02F4u1AOc=
gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E=
gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y=
gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
1 change: 1 addition & 0 deletions pkg/beacon/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,7 @@ func (d *Default) ListFinalizedSlots(ctx context.Context) ([]phase0.Slot, error)

latestSlot := phase0.Slot(uint64(finality.Finalized.Epoch) * uint64(sp.SlotsPerEpoch))

//nolint:gosec // HistoricalEpochCount is validated as positive in config.
for i, val := uint64(latestSlot), uint64(latestSlot)-uint64(sp.SlotsPerEpoch)*uint64(d.config.HistoricalEpochCount); i > val; i -= uint64(sp.SlotsPerEpoch) {
slots = append(slots, phase0.Slot(i))
}
Expand Down
16 changes: 10 additions & 6 deletions pkg/beacon/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,13 +173,13 @@ func (d *Default) fetchHistoricalCheckpoints(ctx context.Context, checkpoint *v1
// We'll derive the current finalized slot and then work back in intervals of SLOTS_PER_EPOCH.
currentSlot := uint64(checkpoint.Finalized.Epoch) * uint64(sp.SlotsPerEpoch)
for i := 1; i < d.config.HistoricalEpochCount; i++ {
//nolint:gosec // i starts at 1 and increments, always positive.
if uint64(i)*uint64(sp.SlotsPerEpoch) > currentSlot {
break
}

slot := phase0.Slot(currentSlot - uint64(i)*uint64(sp.SlotsPerEpoch))

slotsInScope[slot] = struct{}{}
//nolint:gosec // i starts at 1 and increments, always positive.
slotsInScope[phase0.Slot(currentSlot-uint64(i)*uint64(sp.SlotsPerEpoch))] = struct{}{}
}

for slot := range slotsInScope {
Expand Down Expand Up @@ -352,10 +352,14 @@ func (d *Default) fetchBundle(ctx context.Context, root phase0.Root, upstream *N
denebFork, err := sp.ForkEpochs.GetByName("deneb")
if err == nil && denebFork != nil {
if denebFork.Active(epoch) {
// Check if Fulu is active - if so, don't fetch blobs as they're no longer in blocks
// Check if Fulu or Gloas is active - if so, don't fetch blobs as they're no longer in blocks
fuluFork, fuluErr := sp.ForkEpochs.GetByName("fulu")
if fuluErr == nil && fuluFork != nil && fuluFork.Active(epoch) {
d.log.WithField("epoch", epoch).Debug("Skipping blob sidecar download - Fulu fork active")
gloasFork, gloasErr := sp.ForkEpochs.GetByName("gloas")
fuluActive := fuluErr == nil && fuluFork != nil && fuluFork.Active(epoch)
gloasActive := gloasErr == nil && gloasFork != nil && gloasFork.Active(epoch)

if fuluActive || gloasActive {
d.log.WithField("epoch", epoch).Debug("Skipping blob sidecar download - Fulu/Gloas fork active")
Comment thread
qu0b marked this conversation as resolved.
Outdated
} else {
// Download and store blob sidecars
if err := d.downloadAndStoreBlobSidecars(ctx, slot, upstream); err != nil {
Expand Down
2 changes: 2 additions & 0 deletions pkg/beacon/expire_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ var (
)

func CalculateSlotExpiration(slot phase0.Slot, slotsOfHistory int) phase0.Slot {
//nolint:gosec // slotsOfHistory is a small positive test value
return slot + phase0.Slot(slotsOfHistory)
}

func GetSlotTime(slot phase0.Slot, secondsPerSlot time.Duration, genesis time.Time) time.Time {
//nolint:gosec // slot values are within safe range for time.Duration
return genesis.Add(time.Duration(slot) * secondsPerSlot)
}

Expand Down
57 changes: 33 additions & 24 deletions pkg/beacon/ssz/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,25 @@ func (e *Encoder) SetSpec(newSpec *state.Spec) {
e.dynssz = nil
}

func (e *Encoder) marshalSSZ(obj sszutils.FastsszMarshaler) ([]byte, error) {
var (
ssz []byte
err error
)

if e.customPreset {
ssz, err = e.getDynamicSSZ().MarshalSSZ(obj)
} else {
ssz, err = obj.MarshalSSZ()
}

if err != nil {
return nil, err
}

return ssz, nil
}

func (e *Encoder) GetBlockRoot(block *spec.VersionedSignedBeaconBlock) (root phase0.Root, err error) {
var blockObj sszutils.FastsszHashRoot

Expand All @@ -63,6 +82,8 @@ func (e *Encoder) GetBlockRoot(block *spec.VersionedSignedBeaconBlock) (root pha
blockObj = block.Electra.Message
case spec.DataVersionFulu:
blockObj = block.Fulu.Message
case spec.DataVersionGloas:
blockObj = block.Gloas.Message
default:
return phase0.Root{}, errors.New("unknown block version")
}
Expand All @@ -80,7 +101,7 @@ func (e *Encoder) GetBlockRoot(block *spec.VersionedSignedBeaconBlock) (root pha
return root, nil
}

func (e *Encoder) EncodeBlockSSZ(block *spec.VersionedSignedBeaconBlock) (ssz []byte, err error) {
func (e *Encoder) EncodeBlockSSZ(block *spec.VersionedSignedBeaconBlock) ([]byte, error) {
var blockObj sszutils.FastsszMarshaler

switch block.Version {
Expand All @@ -98,21 +119,13 @@ func (e *Encoder) EncodeBlockSSZ(block *spec.VersionedSignedBeaconBlock) (ssz []
blockObj = block.Electra
case spec.DataVersionFulu:
blockObj = block.Fulu
case spec.DataVersionGloas:
blockObj = block.Gloas
default:
return nil, errors.New("unknown block version")
}

if e.customPreset {
ssz, err = e.getDynamicSSZ().MarshalSSZ(blockObj)
} else {
ssz, err = blockObj.MarshalSSZ()
}

if err != nil {
return nil, err
}

return ssz, nil
return e.marshalSSZ(blockObj)
}

func (e *Encoder) EncodeBlockJSON(block *spec.VersionedSignedBeaconBlock) ([]byte, error) {
Expand All @@ -133,6 +146,8 @@ func (e *Encoder) EncodeBlockJSON(block *spec.VersionedSignedBeaconBlock) ([]byt
blockObj = block.Electra
case spec.DataVersionFulu:
blockObj = block.Fulu
case spec.DataVersionGloas:
blockObj = block.Gloas
default:
return nil, errors.New("unknown block version")
}
Expand Down Expand Up @@ -163,6 +178,8 @@ func (e *Encoder) GetStateRoot(beaconState *spec.VersionedBeaconState) (root pha
stateObj = beaconState.Electra
case spec.DataVersionFulu:
stateObj = beaconState.Fulu
case spec.DataVersionGloas:
stateObj = beaconState.Gloas
default:
return phase0.Root{}, errors.New("unknown state version")
}
Expand All @@ -179,7 +196,7 @@ func (e *Encoder) GetStateRoot(beaconState *spec.VersionedBeaconState) (root pha

return root, nil
}
func (e *Encoder) EncodeStateSSZ(beaconState *spec.VersionedBeaconState) (ssz []byte, err error) {
func (e *Encoder) EncodeStateSSZ(beaconState *spec.VersionedBeaconState) ([]byte, error) {
var stateObj sszutils.FastsszMarshaler

switch beaconState.Version {
Expand All @@ -197,19 +214,11 @@ func (e *Encoder) EncodeStateSSZ(beaconState *spec.VersionedBeaconState) (ssz []
stateObj = beaconState.Electra
case spec.DataVersionFulu:
stateObj = beaconState.Fulu
case spec.DataVersionGloas:
stateObj = beaconState.Gloas
default:
return nil, errors.New("unknown state version")
}

if e.customPreset {
ssz, err = e.getDynamicSSZ().MarshalSSZ(stateObj)
} else {
ssz, err = stateObj.MarshalSSZ()
}

if err != nil {
return nil, err
}

return ssz, nil
return e.marshalSSZ(stateObj)
}
2 changes: 2 additions & 0 deletions pkg/cache/ttl.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func NewTTLMap(maxItems int, name, namespace string) (m *TTLMap) {
go func() {
for now := range time.Tick(time.Second * 1) {
m.l.Lock()

for k, v := range m.m {
if v.invincible {
continue
Expand All @@ -49,6 +50,7 @@ func NewTTLMap(maxItems int, name, namespace string) (m *TTLMap) {
m.delete(k, v.value, v.expiresAt)
}
}

m.l.Unlock()
}
}()
Expand Down
1 change: 1 addition & 0 deletions pkg/eth/slot.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type SlotTime struct {
}

func CalculateSlotTime(slot phase0.Slot, genesisTime time.Time, durationPerSlot time.Duration) SlotTime {
//nolint:gosec // slot values are within safe range for time.Duration
slotStartTime := genesisTime.Add(time.Duration(slot) * durationPerSlot).UTC()

return SlotTime{
Expand Down
4 changes: 4 additions & 0 deletions pkg/service/eth/block_id.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ func NewSlotFromString(id string) (phase0.Slot, error) {
return 0, err
}

if slot < 0 {
return 0, errors.New("slot cannot be negative")
}

return phase0.Slot(slot), nil
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/service/eth/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,7 @@ func (h *Handler) BlobSidecars(ctx context.Context, blockID BlockIdentifier, ind

// Find the sidecar with the given index
for i, sidecar := range sidecars {
if index == int(sidecar.Index) {
if deneb.BlobIndex(index) == sidecar.Index {
filtered = append(filtered, sidecars[i])

break
Expand Down
2 changes: 2 additions & 0 deletions web/src/parts/slot/Slot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ export default function Slot(props: { slot: number }) {
return data?.data?.block?.Electra;
case 'FULU':
return data?.data?.block?.Fulu;
case 'GLOAS':
return data?.data?.block?.Gloas;
case 'PHASE0':
return data?.data?.block?.Phase0;
}
Expand Down
3 changes: 2 additions & 1 deletion web/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,15 @@ export interface APIBeaconBlockMessage {
}

export interface APIBeaconBlock {
Version: 'BELLATRIX' | 'ALTAIR' | 'PHASE0' | 'CAPELLA' | 'DENEB' | 'ELECTRA' | 'FULU';
Version: 'BELLATRIX' | 'ALTAIR' | 'PHASE0' | 'CAPELLA' | 'DENEB' | 'ELECTRA' | 'FULU' | 'GLOAS';
Altair?: APIBeaconBlockMessage;
Bellatrix?: APIBeaconBlockMessage;
Capella?: APIBeaconBlockMessage;
Deneb?: APIBeaconBlockMessage;
Phase0?: APIBeaconBlockMessage;
Electra?: APIBeaconBlockMessage;
Fulu?: APIBeaconBlockMessage;
Gloas?: APIBeaconBlockMessage;
}

export interface APIBeaconSlotBlock {
Expand Down
Loading