Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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/pk910/go-eth2-client v0.0.0-20260105163749-315f81992d43

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,10 +154,10 @@ 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/pk910/go-eth2-client v0.0.0-20260105163749-315f81992d43 h1:/IpWWFnimzNdpoGenmPVq6BD8y5POquB+rV9WGZ0FTo=
github.com/pk910/go-eth2-client v0.0.0-20260105163749-315f81992d43/go.mod h1:fvULSL9WtNskkOB4i+Yyr6BKpNHXvmpGZj9969fCrfY=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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
10 changes: 6 additions & 4 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 @@ -354,7 +354,9 @@ func (d *Default) fetchBundle(ctx context.Context, root phase0.Root, upstream *N
if denebFork.Active(epoch) {
// Check if Fulu 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) {
fuluActive := fuluErr == nil && fuluFork != nil && fuluFork.Active(epoch)

if fuluActive {
d.log.WithField("epoch", epoch).Debug("Skipping blob sidecar download - Fulu fork active")
} else {
// Download and store blob sidecars
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