diff --git a/go.mod b/go.mod index 47800be1..7d96c105 100644 --- a/go.mod +++ b/go.mod @@ -6,15 +6,16 @@ require ( github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9 github.com/creasty/defaults v1.6.0 github.com/ethpandaops/beacon v0.69.0 - github.com/ethpandaops/ethwallclock v0.2.0 - github.com/ethpandaops/go-eth2-client v0.1.6 + github.com/ethpandaops/ethwallclock v0.5.0 + github.com/ethpandaops/go-eth2-client v0.1.11 github.com/go-co-op/gocron v1.18.0 github.com/julienschmidt/httprouter v1.3.0 github.com/nanmu42/gzip v1.2.0 - github.com/pk910/dynamic-ssz v1.3.2 + github.com/pk910/dynamic-ssz v1.3.3-0.20260921152246-990798fa9718 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.23.2 github.com/sirupsen/logrus v1.9.3 + github.com/spf13/cast v1.10.0 github.com/spf13/cobra v1.6.1 github.com/stretchr/testify v1.12.1 gopkg.in/yaml.v2 v2.4.0 @@ -24,7 +25,6 @@ require ( github.com/OffchainLabs/go-bitfield v0.0.0-20251031151322-f427d04d8506 // indirect github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/casbin/govaluate v1.10.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/ethereum/go-ethereum v1.17.2-0.20260324190457-8f361e342cb9 // indirect @@ -50,7 +50,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/pk910/hashtree-bindings v0.2.2 // indirect + github.com/pk910/hashtree-bindings v0.2.6 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.66.1 // indirect github.com/prometheus/procfs v0.16.1 // indirect @@ -58,7 +58,6 @@ require ( github.com/robfig/cron/v3 v3.0.1 // indirect github.com/rs/zerolog v1.32.0 // indirect github.com/signalsciences/ac v1.2.0 // indirect - github.com/spf13/cast v1.10.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect github.com/ugorji/go/codec v1.2.6 // indirect diff --git a/go.sum b/go.sum index 392509e0..93c819e3 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,6 @@ github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608 github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI= 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.10.0 h1:ffGw51/hYH3w3rZcxO/KcaUIDOLP84w7nsidMVgaDG0= -github.com/casbin/govaluate v1.10.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9 h1:xz6Nv3zcwO2Lila35hcb0QloCQsc38Al13RNEzWRpX4= @@ -26,10 +24,10 @@ github.com/ethereum/go-ethereum v1.17.2-0.20260324190457-8f361e342cb9 h1:87oCZDe github.com/ethereum/go-ethereum v1.17.2-0.20260324190457-8f361e342cb9/go.mod h1:KHcRXfGOUfUmKg51IhQ0IowiqZ6PqZf08CMtk0g5K1o= github.com/ethpandaops/beacon v0.69.0 h1:qGfy9y+zp8qLna6dgxvzLfAsAdGez0JL8BFJjr1Zudo= github.com/ethpandaops/beacon v0.69.0/go.mod h1:TSvV8MOrn2kfWgWEFOg5b3AvlMLF5BWbkpsMPPGf4/I= -github.com/ethpandaops/ethwallclock v0.2.0 h1:EeFKtZ7v6TAdn/oAh0xaPujD7N4amjBxrWIByraUfLM= -github.com/ethpandaops/ethwallclock v0.2.0/go.mod h1:y0Cu+mhGLlem19vnAV2x0hpFS5KZ7oOi2SWYayv9l24= -github.com/ethpandaops/go-eth2-client v0.1.6 h1:lG7Xz767YQQ+mN1ldzqJlj9Klg6zOElcemjXbCgJV5o= -github.com/ethpandaops/go-eth2-client v0.1.6/go.mod h1:97Oq3omOQSGPPYgrbsOIIw2Pc4T5Ph21f8ZRyHJQBHU= +github.com/ethpandaops/ethwallclock v0.5.0 h1:UZmH3uKHZTZczMGz0ZMTIHTY5q5vNkczfo7eZgOGn5o= +github.com/ethpandaops/ethwallclock v0.5.0/go.mod h1:y0Cu+mhGLlem19vnAV2x0hpFS5KZ7oOi2SWYayv9l24= +github.com/ethpandaops/go-eth2-client v0.1.11 h1:gQErMw/Kc5zZYk4XeZkD27yEn4DPlzaMHlEiuflIluE= +github.com/ethpandaops/go-eth2-client v0.1.11/go.mod h1:sIVbaug0GsltsJS+hj8ID4dmWBIt8TXoNIesvuBCGt0= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -146,10 +144,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 v1.3.2 h1:65UR/O+ss+U2Dn86Rdl7LwehHo3u2ElutduS/pcuUXE= -github.com/pk910/dynamic-ssz v1.3.2/go.mod h1:lqmnou2bjr2UWQ3C/L3082TGW0SFl/SwT7ionwM0+FU= -github.com/pk910/hashtree-bindings v0.2.2 h1:gkczxxekBW2NeMK9N3OLj7Jepe7zPmJGVwr8LyofGsA= -github.com/pk910/hashtree-bindings v0.2.2/go.mod h1:zrWt88783JmhBfcgni6kkIMYRdXTZi/FL//OyI5T/l4= +github.com/pk910/dynamic-ssz v1.3.3-0.20260921152246-990798fa9718 h1:ctdxKDq6c360JEH5gkS6jupRpyRO9BYTTPEdE6RUDuQ= +github.com/pk910/dynamic-ssz v1.3.3-0.20260921152246-990798fa9718/go.mod h1:mnRbhjX+4YMyP4jYMncTUA3aDpMzBLqAbjcvfCyOyRI= +github.com/pk910/hashtree-bindings v0.2.6 h1:BjRQho04nWzGrXwBCLVTyQRNV30O59iPcvQRcidFt2o= +github.com/pk910/hashtree-bindings v0.2.6/go.mod h1:zrWt88783JmhBfcgni6kkIMYRdXTZi/FL//OyI5T/l4= 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= diff --git a/pkg/beacon/default.go b/pkg/beacon/default.go index 5b7012be..7fa0d309 100644 --- a/pkg/beacon/default.go +++ b/pkg/beacon/default.go @@ -24,6 +24,7 @@ import ( "github.com/go-co-op/gocron" perrors "github.com/pkg/errors" "github.com/sirupsen/logrus" + "github.com/spf13/cast" ) const ( @@ -53,6 +54,9 @@ type Default struct { spec *state.Spec genesis *v1.Genesis + clockMutex sync.Mutex + clock *ethwallclock.EthereumBeaconChain + historicalSlotFailures map[phase0.Slot]int servingMutex sync.Mutex @@ -786,18 +790,46 @@ func (d *Default) PeerCount(ctx context.Context) (uint64, error) { } func (d *Default) GetSlotTime(ctx context.Context, slot phase0.Slot) (eth.SlotTime, error) { - SlotTime := eth.SlotTime{} + clock, err := d.wallclock() + if err != nil { + return eth.SlotTime{}, err + } - _, err := d.Spec() + s := clock.Slots().FromNumber(uint64(slot)) + window := s.TimeWindow() + + return eth.SlotTime{ + StartTime: window.Start().UTC(), + EndTime: window.End().UTC(), + }, nil +} + +func (d *Default) wallclock() (*ethwallclock.EthereumBeaconChain, error) { + sp, err := d.Spec() if err != nil { - return SlotTime, errors.New("no upstream beacon state spec available") + return nil, errors.New("no upstream beacon state spec available") } if d.genesis == nil { - return SlotTime, errors.New("genesis time is unknown") + return nil, errors.New("genesis time is unknown") + } + + d.clockMutex.Lock() + defer d.clockMutex.Unlock() + + if d.clock == nil { + d.clock = ethwallclock.NewEthereumBeaconChain( + d.genesis.GenesisTime, + sp.SecondsPerSlot.AsDuration(), + uint64(sp.SlotsPerEpoch), + ethwallclock.WithHezeSlotDuration( + cast.ToUint64(sp.FullSpec["HEZE_FORK_EPOCH"]), + time.Duration(cast.ToInt64(sp.FullSpec["SLOT_DURATION_MS_HEZE"]))*time.Millisecond, + ), + ) } - return eth.CalculateSlotTime(slot, d.genesis.GenesisTime, d.spec.SecondsPerSlot.AsDuration()), nil + return d.clock, nil } func (d *Default) GetDepositSnapshot(ctx context.Context, epoch phase0.Epoch) (*types.DepositSnapshot, error) { diff --git a/pkg/beacon/ssz/encoder.go b/pkg/beacon/ssz/encoder.go index ad48cfb8..f442bcd0 100644 --- a/pkg/beacon/ssz/encoder.go +++ b/pkg/beacon/ssz/encoder.go @@ -84,6 +84,8 @@ func (e *Encoder) GetBlockRoot(block *spec.VersionedSignedBeaconBlock) (root pha blockObj = block.Fulu.Message case spec.DataVersionGloas: blockObj = block.Gloas.Message + case spec.DataVersionHeze: + blockObj = block.Heze.Message default: return phase0.Root{}, errors.New("unknown block version") } @@ -121,6 +123,8 @@ func (e *Encoder) EncodeBlockSSZ(block *spec.VersionedSignedBeaconBlock) ([]byte blockObj = block.Fulu case spec.DataVersionGloas: blockObj = block.Gloas + case spec.DataVersionHeze: + blockObj = block.Heze default: return nil, errors.New("unknown block version") } @@ -148,6 +152,8 @@ func (e *Encoder) EncodeBlockJSON(block *spec.VersionedSignedBeaconBlock) ([]byt blockObj = block.Fulu case spec.DataVersionGloas: blockObj = block.Gloas + case spec.DataVersionHeze: + blockObj = block.Heze default: return nil, errors.New("unknown block version") } @@ -180,6 +186,8 @@ func (e *Encoder) GetStateRoot(beaconState *spec.VersionedBeaconState) (root pha stateObj = beaconState.Fulu case spec.DataVersionGloas: stateObj = beaconState.Gloas + case spec.DataVersionHeze: + stateObj = beaconState.Heze default: return phase0.Root{}, errors.New("unknown state version") } @@ -216,6 +224,8 @@ func (e *Encoder) EncodeStateSSZ(beaconState *spec.VersionedBeaconState) ([]byte stateObj = beaconState.Fulu case spec.DataVersionGloas: stateObj = beaconState.Gloas + case spec.DataVersionHeze: + stateObj = beaconState.Heze default: return nil, errors.New("unknown state version") } diff --git a/pkg/eth/slot.go b/pkg/eth/slot.go index 375696da..2796f92d 100644 --- a/pkg/eth/slot.go +++ b/pkg/eth/slot.go @@ -2,8 +2,6 @@ package eth import ( "time" - - "github.com/ethpandaops/go-eth2-client/spec/phase0" ) type SlotTime struct { @@ -12,13 +10,3 @@ type SlotTime struct { // The time at which the slot ends. EndTime time.Time `json:"end_time"` } - -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{ - StartTime: slotStartTime, - EndTime: slotStartTime.Add(durationPerSlot), - } -} diff --git a/pkg/eth/slot_test.go b/pkg/eth/slot_test.go deleted file mode 100644 index d2c7c85d..00000000 --- a/pkg/eth/slot_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package eth - -import ( - "reflect" - "testing" - "time" - - "github.com/ethpandaops/go-eth2-client/spec/phase0" -) - -func TestCalculateSlotTime(t *testing.T) { - genesisTime := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC) - durationPerSlot := time.Second * 12 - - tests := []struct { - name string - slot phase0.Slot - want SlotTime - }{ - { - name: "genesis slot", - slot: phase0.Slot(0), - want: SlotTime{ - StartTime: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC), - EndTime: time.Date(2020, 1, 1, 0, 0, 12, 0, time.UTC), - }, - }, - { - name: "first slot", - slot: phase0.Slot(1), - want: SlotTime{ - StartTime: time.Date(2020, 1, 1, 0, 0, 12, 0, time.UTC), - EndTime: time.Date(2020, 1, 1, 0, 0, 24, 0, time.UTC), - }, - }, - { - name: "slot 100", - slot: phase0.Slot(100), - want: SlotTime{ - StartTime: time.Date(2020, 1, 1, 0, 20, 0, 0, time.UTC), - EndTime: time.Date(2020, 1, 1, 0, 20, 12, 0, time.UTC), - }, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - got := CalculateSlotTime(test.slot, genesisTime, durationPerSlot) - if !reflect.DeepEqual(got, test.want) { - t.Errorf("CalculateSlotTime() = %v, want %v", got, test.want) - } - }) - } -} diff --git a/web/src/parts/slot/Slot.tsx b/web/src/parts/slot/Slot.tsx index 605350ab..87ac2332 100644 --- a/web/src/parts/slot/Slot.tsx +++ b/web/src/parts/slot/Slot.tsx @@ -40,6 +40,8 @@ export default function Slot(props: { slot: number }) { return data?.data?.block?.Fulu; case 'GLOAS': return data?.data?.block?.Gloas; + case 'HEZE': + return data?.data?.block?.Heze; case 'PHASE0': return data?.data?.block?.Phase0; } diff --git a/web/src/types/index.ts b/web/src/types/index.ts index 53a2291f..7973d19e 100644 --- a/web/src/types/index.ts +++ b/web/src/types/index.ts @@ -76,7 +76,7 @@ export interface APIBeaconBlockMessage { } export interface APIBeaconBlock { - Version: 'BELLATRIX' | 'ALTAIR' | 'PHASE0' | 'CAPELLA' | 'DENEB' | 'ELECTRA' | 'FULU' | 'GLOAS'; + Version: 'BELLATRIX' | 'ALTAIR' | 'PHASE0' | 'CAPELLA' | 'DENEB' | 'ELECTRA' | 'FULU' | 'GLOAS' | 'HEZE'; Altair?: APIBeaconBlockMessage; Bellatrix?: APIBeaconBlockMessage; Capella?: APIBeaconBlockMessage; @@ -85,6 +85,7 @@ export interface APIBeaconBlock { Electra?: APIBeaconBlockMessage; Fulu?: APIBeaconBlockMessage; Gloas?: APIBeaconBlockMessage; + Heze?: APIBeaconBlockMessage; } export interface APIBeaconSlotBlock {