Skip to content

Commit

Permalink
core/validatorapi: relax SlotFromTimestamp checks (#3066)
Browse files Browse the repository at this point in the history
Export `SlotFromTimestamp` instead of keeping two equal implementation.

Relax `SlotFromTimestamp` timestamp checks: if a timestamp comes before genesis time as fetched from the beacon node, fall back to `time.Now()` as timestamp.

This function is only ever used to check for validator registration validity, which has never been formalized and can be relaxed.

category: refactor
ticket: none
  • Loading branch information
gsora authored May 6, 2024
1 parent 11e3000 commit c51af10
Show file tree
Hide file tree
Showing 16 changed files with 151 additions and 150 deletions.
28 changes: 2 additions & 26 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -647,12 +647,12 @@ func wireRecaster(ctx context.Context, eth2Cl eth2wrap.Client, sched core.Schedu
return errors.Wrap(err, "new versioned signed validator registration")
}

slot, err := slotFromTimestamp(ctx, eth2Cl, reg.V1.Message.Timestamp)
slot, err := validatorapi.SlotFromTimestamp(ctx, eth2Cl, reg.V1.Message.Timestamp)
if err != nil {
return errors.Wrap(err, "calculate slot from timestamp")
}

if err = recaster.Store(ctx, core.NewBuilderRegistrationDuty(slot), core.SignedDataSet{pubkey: signedData}); err != nil {
if err = recaster.Store(ctx, core.NewBuilderRegistrationDuty(uint64(slot)), core.SignedDataSet{pubkey: signedData}); err != nil {
return errors.Wrap(err, "recaster store registration")
}
}
Expand Down Expand Up @@ -1062,27 +1062,3 @@ func hex7(input []byte) string {

return resp[:7]
}

// slotFromTimestamp returns slot from the provided timestamp.
func slotFromTimestamp(ctx context.Context, eth2Cl eth2wrap.Client, timestamp time.Time) (uint64, error) {
genesis, err := eth2Cl.GenesisTime(ctx)
if err != nil {
return 0, err
} else if timestamp.Before(genesis) {
return 0, errors.New("registration timestamp before genesis")
}

eth2Resp, err := eth2Cl.Spec(ctx, &eth2api.SpecOpts{})
if err != nil {
return 0, err
}

slotDuration, ok := eth2Resp.Data["SECONDS_PER_SLOT"].(time.Duration)
if !ok {
return 0, errors.New("fetch slot duration")
}

delta := timestamp.Sub(genesis)

return uint64(delta / slotDuration), nil
}
86 changes: 0 additions & 86 deletions app/app_internal_test.go

This file was deleted.

2 changes: 1 addition & 1 deletion app/log/loki/lokipb/v1/loki.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion app/peerinfo/peerinfopb/v1/peerinfo.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion app/protonil/testdata/v1/test.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cluster/manifestpb/v1/manifest.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion core/corepb/v1/consensus.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion core/corepb/v1/core.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion core/corepb/v1/parsigex.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion core/corepb/v1/priority.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

65 changes: 39 additions & 26 deletions core/validatorapi/validatorapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,42 @@ const (
zeroAddress = "0x0000000000000000000000000000000000000000"
)

// SlotFromTimestamp returns the Ethereum slot associated to a timestamp, given the genesis configuration fetched
// from client.
func SlotFromTimestamp(ctx context.Context, client eth2wrap.Client, timestamp time.Time) (eth2p0.Slot, error) {
genesis, err := client.GenesisTime(ctx)
if err != nil {
return 0, err
} else if timestamp.Before(genesis) {
// if timestamp is in the past (can happen in testing scenarios, there's no strict form of checking on it), fall back on current timestamp.
nextTimestamp := time.Now()

log.Info(
ctx,
"timestamp before genesis, defaulting to current timestamp",
z.I64("genesis_timestamp", genesis.Unix()),
z.I64("overridden_timestamp", timestamp.Unix()),
z.I64("new_timestamp", nextTimestamp.Unix()),
)

timestamp = nextTimestamp
}

eth2Resp, err := client.Spec(ctx, &eth2api.SpecOpts{})
if err != nil {
return 0, err
}

slotDuration, ok := eth2Resp.Data["SECONDS_PER_SLOT"].(time.Duration)
if !ok {
return 0, errors.New("fetch slot duration")
}

delta := timestamp.Sub(genesis)

return eth2p0.Slot(delta / slotDuration), nil
}

// NewComponentInsecure returns a new instance of the validator API core workflow component
// that does not perform signature verification.
func NewComponentInsecure(_ *testing.T, eth2Cl eth2wrap.Client, shareIdx int) (*Component, error) {
Expand Down Expand Up @@ -461,7 +497,7 @@ func (c Component) submitRegistration(ctx context.Context, registration *eth2api
if err != nil {
return err
}
slot, err := c.slotFromTimestamp(ctx, timestamp)
slot, err := SlotFromTimestamp(ctx, c.eth2Cl, timestamp)
if err != nil {
return err
}
Expand Down Expand Up @@ -499,7 +535,7 @@ func (c Component) SubmitValidatorRegistrations(ctx context.Context, registratio
return nil // Nothing to do
}

slot, err := c.slotFromTimestamp(ctx, time.Now())
slot, err := SlotFromTimestamp(ctx, c.eth2Cl, time.Now())
if err != nil {
return err
}
Expand Down Expand Up @@ -981,29 +1017,6 @@ func (c Component) convertValidators(vals map[eth2p0.ValidatorIndex]*eth2v1.Vali
return resp, nil
}

func (c Component) slotFromTimestamp(ctx context.Context, timestamp time.Time) (eth2p0.Slot, error) {
genesis, err := c.eth2Cl.GenesisTime(ctx)
if err != nil {
return 0, err
} else if timestamp.Before(genesis) {
return 0, errors.New("registration timestamp before genesis")
}

eth2Resp, err := c.eth2Cl.Spec(ctx, &eth2api.SpecOpts{})
if err != nil {
return 0, err
}

slotDuration, ok := eth2Resp.Data["SECONDS_PER_SLOT"].(time.Duration)
if !ok {
return 0, errors.New("fetch slot duration")
}

delta := timestamp.Sub(genesis)

return eth2p0.Slot(delta / slotDuration), nil
}

func (c Component) getProposerPubkey(ctx context.Context, duty core.Duty) (core.PubKey, error) {
// Get proposer pubkey (this is a blocking query).
defSet, err := c.dutyDefFunc(ctx, duty)
Expand Down Expand Up @@ -1115,7 +1128,7 @@ func (c Component) ProposerConfig(ctx context.Context) (*eth2exp.ProposerConfigR
}
timestamp = timestamp.Add(slotDuration) // Use slot 1 for timestamp to override pre-generated registrations.

slot, err := c.slotFromTimestamp(ctx, time.Now())
slot, err := SlotFromTimestamp(ctx, c.eth2Cl, time.Now())
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit c51af10

Please sign in to comment.