Skip to content
Closed
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
13 changes: 4 additions & 9 deletions cmd/hermes/cmd_eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"log/slog"
"time"

"github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing"
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p"
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/encoder"
"github.com/OffchainLabs/prysm/v6/config/params"
Expand Down Expand Up @@ -415,27 +414,23 @@ func cmdEthAction(c *cli.Context) error {
config = c
}

// Overriding configuration so that functions like ComputForkDigest take the
// correct input data from the global configuration.
// Overriding configuration so that params.ForkDigest and other functions
// use the correct network configuration.
params.OverrideBeaconConfig(config.Beacon)
params.OverrideBeaconNetworkConfig(config.Network)

genesisRoot := config.Genesis.GenesisValidatorRoot
genesisTime := config.Genesis.GenesisTime

// compute fork version and fork digest
currentSlot := slots.Since(genesisTime)
currentSlot := slots.CurrentSlot(genesisTime)
currentEpoch := slots.ToEpoch(currentSlot)

currentForkVersion, err := eth.GetCurrentForkVersion(currentEpoch, config.Beacon)
if err != nil {
return fmt.Errorf("compute fork version for epoch %d: %w", currentEpoch, err)
}

forkDigest, err := signing.ComputeForkDigest(currentForkVersion[:], genesisRoot)
if err != nil {
return fmt.Errorf("create fork digest (%s, %x): %w", genesisTime, genesisRoot, err)
}
forkDigest := params.ForkDigest(currentEpoch)

cfg := &eth.NodeConfig{
GenesisConfig: config.Genesis,
Expand Down
11 changes: 6 additions & 5 deletions cmd/hermes/cmd_eth_chains.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"log/slog"
"math"

"github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/urfave/cli/v2"

Expand Down Expand Up @@ -35,13 +34,18 @@ func cmdEthChainsAction(c *cli.Context) error {
}
slog.Info(chain)

// Override params config for this network to get correct fork digests.
params.OverrideBeaconConfig(config.Beacon)
params.OverrideBeaconNetworkConfig(config.Network)

forkVersions := [][]byte{
config.Beacon.GenesisForkVersion,
config.Beacon.AltairForkVersion,
config.Beacon.BellatrixForkVersion,
config.Beacon.CapellaForkVersion,
config.Beacon.DenebForkVersion,
config.Beacon.ElectraForkVersion,
config.Beacon.FuluForkVersion,
}

for _, forkVersion := range forkVersions {
Expand All @@ -59,10 +63,7 @@ func cmdEthChainsAction(c *cli.Context) error {
continue
}

digest, err := signing.ComputeForkDigest(forkVersion, config.Genesis.GenesisValidatorRoot)
if err != nil {
return err
}
digest := params.ForkDigest(epoch)

slog.Info(fmt.Sprintf("- %s: 0x%x (epoch %d)", forkName, digest, epoch))
}
Expand Down
14 changes: 6 additions & 8 deletions eth/discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import (
"log/slog"
"net"

"github.com/OffchainLabs/prysm/v6/network/forks"
"github.com/OffchainLabs/prysm/v6/config/params"
pb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/time/slots"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
Expand Down Expand Up @@ -93,13 +94,10 @@ func (d *Discovery) Serve(ctx context.Context) (err error) {
defer slog.Info("Stopped disv5 Discovery Service")
defer func() { err = terminateSupervisorTreeOnErr(err) }()

genesisRoot := d.cfg.GenesisConfig.GenesisValidatorRoot
genesisTime := d.cfg.GenesisConfig.GenesisTime

digest, err := forks.CreateForkDigest(genesisTime, genesisRoot)
if err != nil {
return fmt.Errorf("create fork digest (%s, %x): %w", genesisTime, genesisRoot, err)
}
currentSlot := slots.CurrentSlot(genesisTime)
currentEpoch := slots.ToEpoch(currentSlot)
digest := params.ForkDigest(currentEpoch)

ip := net.ParseIP(d.cfg.Addr)

Expand Down Expand Up @@ -179,7 +177,7 @@ func (d *Discovery) Serve(ctx context.Context) (err error) {
continue
}
sszEncodedForkEntry := make([]byte, 16)
entry := enr.WithEntry(d.cfg.NetworkConfig.ETH2Key, &sszEncodedForkEntry)
entry := enr.WithEntry("eth2", &sszEncodedForkEntry)
if err = node.Record().Load(entry); err != nil {
// failed reading eth2 enr entry, likely because it doesn't exist
continue
Expand Down
29 changes: 14 additions & 15 deletions eth/discovery_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"fmt"

"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/network/forks"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
pb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/time/slots"
"github.com/ethereum/go-ethereum/p2p/enode"
Expand Down Expand Up @@ -33,20 +33,19 @@ type DiscoveryConfig struct {
// byte slice. Finally, it returns an ENR entry with the eth2 key and the
// encoded fork information.
func (d *DiscoveryConfig) enrEth2Entry() (enr.Entry, error) {
genesisRoot := d.GenesisConfig.GenesisValidatorRoot
genesisTime := d.GenesisConfig.GenesisTime
var (
currentSlot = slots.CurrentSlot(d.GenesisConfig.GenesisTime)
currentEpoch = slots.ToEpoch(currentSlot)
digest = params.ForkDigest(currentEpoch)
nextEntry = params.NextNetworkScheduleEntry(currentEpoch)
nextForkVersion [4]byte
nextForkEpoch primitives.Epoch
)

digest, err := forks.CreateForkDigest(genesisTime, genesisRoot)
if err != nil {
return nil, fmt.Errorf("create fork digest (%s, %x): %w", genesisTime, genesisRoot, err)
}

currentSlot := slots.Since(genesisTime)
currentEpoch := slots.ToEpoch(currentSlot)

nextForkVersion, nextForkEpoch, err := forks.NextForkData(currentEpoch)
if err != nil {
return nil, fmt.Errorf("calculate next fork data: %w", err)
// Is there another fork coming up?
if nextEntry.Epoch > currentEpoch {
copy(nextForkVersion[:], nextEntry.ForkVersion[:])
nextForkEpoch = nextEntry.Epoch
}

enrForkID := &pb.ENRForkID{
Expand All @@ -60,7 +59,7 @@ func (d *DiscoveryConfig) enrEth2Entry() (enr.Entry, error) {
return nil, fmt.Errorf("marshal enr fork id: %w", err)
}

return enr.WithEntry(d.NetworkConfig.ETH2Key, enc), nil
return enr.WithEntry("eth2", enc), nil
}

func (d *DiscoveryConfig) enrAttnetsEntry() enr.Entry {
Expand Down
42 changes: 16 additions & 26 deletions eth/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"
"time"

"github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
)
Expand All @@ -25,6 +24,7 @@ var (
CapellaForkVersion ForkVersion
DenebForkVersion ForkVersion
ElectraForkVersion ForkVersion
FuluForkVersion ForkVersion

GlobalBeaconConfig = params.MainnetConfig() // init with Mainnet (we would override if needed)
)
Expand All @@ -37,6 +37,7 @@ func initNetworkForkVersions(beaconConfig *params.BeaconChainConfig) {
CapellaForkVersion = ForkVersion(beaconConfig.CapellaForkVersion)
DenebForkVersion = ForkVersion(beaconConfig.DenebForkVersion)
ElectraForkVersion = ForkVersion(beaconConfig.ElectraForkVersion)
FuluForkVersion = ForkVersion(beaconConfig.FuluForkVersion)

GlobalBeaconConfig = beaconConfig
}
Expand Down Expand Up @@ -96,38 +97,27 @@ func GetCurrentForkVersion(epoch primitives.Epoch, beaconConfg *params.BeaconCha
case epoch < beaconConfg.ElectraForkEpoch:
return [4]byte(beaconConfg.DenebForkVersion), nil

case epoch >= beaconConfg.ElectraForkEpoch:
case epoch < beaconConfg.FuluForkEpoch:
return [4]byte(beaconConfg.ElectraForkVersion), nil

case epoch >= beaconConfg.FuluForkEpoch:
return [4]byte(beaconConfg.FuluForkVersion), nil

default:
return [4]byte{}, fmt.Errorf("not recognized case for epoch %d", epoch)
}
}

// GetForkVersionFromForkDigest returns the fork version for a given fork digest.
// This function is BPO-aware as it uses params.ForkDataFromDigest which handles
// the network schedule including BPO phases for Fulu+.
func GetForkVersionFromForkDigest(forkD [4]byte) (forkV ForkVersion, err error) {
genesisRoot := GenesisConfigs[GlobalBeaconConfig.ConfigName].GenesisValidatorRoot
phase0D, _ := signing.ComputeForkDigest(Phase0ForkVersion[:], genesisRoot)
altairD, _ := signing.ComputeForkDigest(AltairForkVersion[:], genesisRoot)
bellatrixD, _ := signing.ComputeForkDigest(BellatrixForkVersion[:], genesisRoot)
capellaD, _ := signing.ComputeForkDigest(CapellaForkVersion[:], genesisRoot)
denebD, _ := signing.ComputeForkDigest(DenebForkVersion[:], genesisRoot)
electraD, _ := signing.ComputeForkDigest(ElectraForkVersion[:], genesisRoot)
switch forkD {
case phase0D:
forkV = Phase0ForkVersion
case altairD:
forkV = AltairForkVersion
case bellatrixD:
forkV = BellatrixForkVersion
case capellaD:
forkV = CapellaForkVersion
case denebD:
forkV = DenebForkVersion
case electraD:
forkV = ElectraForkVersion
default:
forkV = ForkVersion{}
err = fmt.Errorf("not recognized fork_version for (%s)", hex.EncodeToString([]byte(forkD[:])))
// Use params.ForkDataFromDigest which is BPO-aware and handles all fork digests
// including those modified by BPO schedule in Fulu+
version, _, err := params.ForkDataFromDigest(forkD)
if err != nil {
return ForkVersion{}, fmt.Errorf("fork digest %s not found in network schedule", hex.EncodeToString(forkD[:]))
}
return forkV, err

return version, nil
}
1 change: 1 addition & 0 deletions eth/network_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ func DeriveKnownNetworkConfig(ctx context.Context, network string) (*NetworkConf
CapellaForkVersion: []byte{0x03, 0x00, 0x00, 0x64},
DenebForkVersion: []byte{0x04, 0x00, 0x00, 0x64},
ElectraForkVersion: []byte{0x05, 0x00, 0x00, 0x64},
FuluForkVersion: []byte{0x06, 0x00, 0x00, 0x64},
ForkVersionSchedule: map[[4]byte]primitives.Epoch{
{0x00, 0x00, 0x00, 0x64}: primitives.Epoch(0),
{0x01, 0x00, 0x00, 0x64}: primitives.Epoch(512),
Expand Down
81 changes: 58 additions & 23 deletions eth/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import (
"time"

"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p"
"github.com/OffchainLabs/prysm/v6/config/params"
eth "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/time/slots"
"github.com/aws/aws-sdk-go-v2/service/kinesis"
gk "github.com/dennis-tra/go-kinesis"
"github.com/libp2p/go-libp2p/core/peer"
Expand Down Expand Up @@ -195,6 +197,8 @@ func NewNode(cfg *NodeConfig) (*Node, error) {
DataStream: ds,
ReadTimeout: cfg.BeaconConfig.TtfbTimeoutDuration(),
WriteTimeout: cfg.BeaconConfig.RespTimeoutDuration(),
BeaconConfig: cfg.BeaconConfig,
GenesisConfig: cfg.GenesisConfig,
Tracer: cfg.Tracer,
Meter: cfg.Meter,
}
Expand All @@ -204,29 +208,26 @@ func NewNode(cfg *NodeConfig) (*Node, error) {
return nil, fmt.Errorf("new p2p server: %w", err)
}

// initialize the pubsub topic handlers
pubSubConfig := &PubSubConfig{
Topics: cfg.getDesiredFullTopics(cfg.GossipSubMessageEncoder),
ForkVersion: cfg.ForkVersion,
Encoder: cfg.GossipSubMessageEncoder,
SecondsPerSlot: time.Duration(cfg.BeaconConfig.SecondsPerSlot) * time.Second,
GenesisTime: cfg.GenesisConfig.GenesisTime,
DataStream: ds,
}

pubSub, err := NewPubSub(h, pubSubConfig)
if err != nil {
return nil, fmt.Errorf("new PubSub service: %w", err)
}

// initialize the custom Prysm client to communicate with its API
pryClient, err := NewPrysmClientWithTLS(cfg.PrysmHost, cfg.PrysmPortHTTP, cfg.PrysmPortGRPC, cfg.PrysmUseTLS, cfg.DialTimeout, cfg.GenesisConfig)
if err != nil {
return nil, fmt.Errorf("new prysm client: %w", err)
}
// check if Prysm is valid

// Fetch and set the BlobSchedule from Prysm for correct BPO fork digest calculation.
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := pryClient.FetchAndSetBlobSchedule(ctx); err != nil {
// Continue even if this fails, as the network might not have BPO enabled.
slog.Warn("Failed to fetch BlobSchedule from Prysm", tele.LogAttrError(err))
}

// Recalculate fork digest after loading BlobSchedule.
currentSlot := slots.CurrentSlot(cfg.GenesisConfig.GenesisTime)
currentEpoch := slots.ToEpoch(currentSlot)
cfg.ForkDigest = params.ForkDigest(currentEpoch)

// check if Prysm is valid
onNetwork, err := pryClient.isOnNetwork(ctx, cfg.ForkDigest)
if err != nil {
return nil, fmt.Errorf("prysm client: %w", err)
Expand All @@ -235,6 +236,20 @@ func NewNode(cfg *NodeConfig) (*Node, error) {
return nil, fmt.Errorf("prysm client not in correct fork_digest")
}

pubSubConfig := &PubSubConfig{
Topics: cfg.getDesiredFullTopics(cfg.GossipSubMessageEncoder),
ForkVersion: cfg.ForkVersion,
Encoder: cfg.GossipSubMessageEncoder,
SecondsPerSlot: time.Duration(cfg.BeaconConfig.SecondsPerSlot) * time.Second,
GenesisTime: cfg.GenesisConfig.GenesisTime,
DataStream: ds,
}

pubSub, err := NewPubSub(h, pubSubConfig)
if err != nil {
return nil, fmt.Errorf("new PubSub service: %w", err)
}

// finally, initialize hermes node
n := &Node{
cfg: cfg,
Expand Down Expand Up @@ -397,14 +412,34 @@ func (n *Node) Start(ctx context.Context) error {
return fmt.Errorf("get finalized finality checkpoints: %w", err)
}

status := &eth.Status{
ForkDigest: n.cfg.ForkDigest[:],
FinalizedRoot: chainHead.FinalizedBlockRoot,
FinalizedEpoch: chainHead.FinalizedEpoch,
HeadRoot: chainHead.HeadBlockRoot,
HeadSlot: chainHead.HeadSlot,
// Determine which status version to use based on the fork
currentSlot := slots.CurrentSlot(n.cfg.GenesisConfig.GenesisTime)
currentEpoch := slots.ToEpoch(currentSlot)

// Use StatusV2 for Fulu fork and later, StatusV1 for earlier forks
if n.cfg.BeaconConfig.FuluForkEpoch != params.BeaconConfig().FarFutureEpoch &&
currentEpoch >= n.cfg.BeaconConfig.FuluForkEpoch {
// Fulu or later - use StatusV2
status := &eth.StatusV2{
ForkDigest: n.cfg.ForkDigest[:],
FinalizedRoot: chainHead.FinalizedBlockRoot,
FinalizedEpoch: chainHead.FinalizedEpoch,
HeadRoot: chainHead.HeadBlockRoot,
HeadSlot: chainHead.HeadSlot,
EarliestAvailableSlot: 0, // TODO: Get actual earliest slot from beacon node
}
n.reqResp.SetStatusV2(status)
} else {
// Pre-Fulu - use StatusV1
status := &eth.Status{
ForkDigest: n.cfg.ForkDigest[:],
FinalizedRoot: chainHead.FinalizedBlockRoot,
FinalizedEpoch: chainHead.FinalizedEpoch,
HeadRoot: chainHead.HeadBlockRoot,
HeadSlot: chainHead.HeadSlot,
}
n.reqResp.SetStatusV1(status)
}
n.reqResp.SetStatus(status)

// Set stream handlers on our libp2p host
if err := n.reqResp.RegisterHandlers(ctx); err != nil {
Expand Down
4 changes: 4 additions & 0 deletions eth/node_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,7 @@ func desiredPubSubBaseTopics() []string {
p2p.GossipSyncCommitteeMessage,
p2p.GossipBlsToExecutionChangeMessage,
p2p.GossipBlobSidecarMessage,
p2p.GossipDataColumnSidecarMessage,
}
}

Expand Down Expand Up @@ -475,6 +476,9 @@ func topicFormatFromBase(topicBase string) (string, error) {
case p2p.GossipBlobSidecarMessage:
return p2p.BlobSubnetTopicFormat, nil

case p2p.GossipDataColumnSidecarMessage:
return p2p.DataColumnSubnetTopicFormat, nil

default:
return "", fmt.Errorf("unrecognized gossip topic base: %s", topicBase)
}
Expand Down
Loading