Use explicit slot component timing configs (#15999)

* Use new timing configs (due BPS)

* Bastin's feedback
This commit is contained in:
terence
2025-11-13 16:55:32 -05:00
committed by GitHub
parent 7ba60d93f2
commit f77b78943a
35 changed files with 402 additions and 100 deletions

View File

@@ -17,6 +17,7 @@ go_library(
"sync_committee.go",
"validator.go",
"wait_for_activation.go",
"wait_helpers.go",
],
importpath = "github.com/OffchainLabs/prysm/v7/validator/client",
visibility = [
@@ -115,6 +116,7 @@ go_test(
"sync_committee_test.go",
"validator_test.go",
"wait_for_activation_test.go",
"wait_helpers_test.go",
],
data = [
"@eip3076_spec_tests//:test_data",

View File

@@ -4,20 +4,17 @@ import (
"context"
"fmt"
"net/http"
"time"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/signing"
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v7/crypto/bls"
"github.com/OffchainLabs/prysm/v7/monitoring/tracing"
"github.com/OffchainLabs/prysm/v7/monitoring/tracing/trace"
"github.com/OffchainLabs/prysm/v7/network/httputil"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
validatorpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1/validator-client"
"github.com/OffchainLabs/prysm/v7/runtime/version"
prysmTime "github.com/OffchainLabs/prysm/v7/time"
"github.com/OffchainLabs/prysm/v7/time/slots"
"github.com/pkg/errors"
"google.golang.org/grpc/codes"
@@ -210,32 +207,7 @@ func (v *validator) signSlotWithSelectionProof(ctx context.Context, pubKey [fiel
// such that any attestations from this slot have time to reach the beacon node
// before creating the aggregated attestation.
func (v *validator) waitToSlotTwoThirds(ctx context.Context, slot primitives.Slot) {
ctx, span := trace.StartSpan(ctx, "validator.waitToSlotTwoThirds")
defer span.End()
oneThird := slots.DivideSlotBy(3 /* one third of slot duration */)
twoThird := oneThird + oneThird
delay := twoThird
startTime, err := slots.StartTime(v.genesisTime, slot)
if err != nil {
log.WithError(err).WithField("slot", slot).Error("Slot overflows, unable to wait for slot two thirds!")
return
}
finalTime := startTime.Add(delay)
wait := prysmTime.Until(finalTime)
if wait <= 0 {
return
}
t := time.NewTimer(wait)
defer t.Stop()
select {
case <-ctx.Done():
tracing.AnnotateError(span, ctx.Err())
return
case <-t.C:
return
}
v.waitUntilSlotComponent(ctx, slot, params.BeaconConfig().AggregrateDueBPS)
}
// This returns the signature of validator signing over aggregate and

View File

@@ -16,7 +16,6 @@ import (
"github.com/OffchainLabs/prysm/v7/testing/assert"
"github.com/OffchainLabs/prysm/v7/testing/require"
"github.com/OffchainLabs/prysm/v7/testing/util"
"github.com/OffchainLabs/prysm/v7/time/slots"
"github.com/OffchainLabs/prysm/v7/validator/client/iface"
logTest "github.com/sirupsen/logrus/hooks/test"
"go.uber.org/mock/gomock"
@@ -256,9 +255,9 @@ func TestWaitForSlotTwoThird_WaitCorrectly(t *testing.T) {
defer finish()
currentTime := time.Now()
numOfSlots := primitives.Slot(4)
validator.genesisTime = currentTime.Add(-1 * time.Duration(numOfSlots.Mul(params.BeaconConfig().SecondsPerSlot)) * time.Second)
oneThird := slots.DivideSlotBy(3 /* one third of slot duration */)
timeToSleep := oneThird + oneThird
slotDuration := params.BeaconConfig().SlotDuration()
validator.genesisTime = currentTime.Add(-slotDuration * time.Duration(numOfSlots))
timeToSleep := params.BeaconConfig().SlotComponentDuration(params.BeaconConfig().AggregrateDueBPS)
twoThirdTime := currentTime.Add(timeToSleep)
validator.waitToSlotTwoThirds(t.Context(), numOfSlots)
@@ -275,7 +274,8 @@ func TestWaitForSlotTwoThird_DoneContext_ReturnsImmediately(t *testing.T) {
defer finish()
currentTime := time.Now()
numOfSlots := primitives.Slot(4)
validator.genesisTime = currentTime.Add(-1 * time.Duration(numOfSlots.Mul(params.BeaconConfig().SecondsPerSlot)) * time.Second)
slotDuration := params.BeaconConfig().SlotDuration()
validator.genesisTime = currentTime.Add(-slotDuration * time.Duration(numOfSlots))
expectedTime := time.Now()
ctx, cancel := context.WithCancel(t.Context())

View File

@@ -280,13 +280,11 @@ func (v *validator) waitOneThirdOrValidBlock(ctx context.Context, slot primitive
return
}
delay := slots.DivideSlotBy(3 /* a third of the slot duration */)
startTime, err := slots.StartTime(v.genesisTime, slot)
finalTime, err := v.slotComponentDeadline(slot, params.BeaconConfig().AttestationDueBPS)
if err != nil {
log.WithError(err).WithField("slot", slot).Error("Slot overflows, unable to wait for slot two thirds!")
log.WithError(err).WithField("slot", slot).Error("Slot overflows, unable to wait for attestation deadline")
return
}
finalTime := startTime.Add(delay)
wait := prysmTime.Until(finalTime)
if wait <= 0 {
return

View File

@@ -373,7 +373,7 @@ func TestRunnerPushesProposerSettings_ValidContext(t *testing.T) {
logrus.SetOutput(tlogger{t})
cfg := params.BeaconConfig()
cfg.SecondsPerSlot = 1
cfg.SlotDurationMilliseconds = 1000
params.SetActiveTestCleanup(t, cfg)
timedCtx, cancel := context.WithTimeout(t.Context(), 1*time.Minute)

View File

@@ -127,7 +127,7 @@ func (v *validator) SubmitSignedContributionAndProof(ctx context.Context, slot p
return
}
v.waitToSlotTwoThirds(ctx, slot)
v.waitUntilSlotComponent(ctx, slot, params.BeaconConfig().ContributionDueBPS)
coveredSubnets := make(map[uint64]bool)
for i, comIdx := range indexRes.Indices {

View File

@@ -54,7 +54,7 @@ func TestWaitForActivation_RefetchKeys(t *testing.T) {
params.SetupTestConfigCleanup(t)
cfg := params.MainnetConfig()
cfg.ConfigName = "test"
cfg.SecondsPerSlot = 1
cfg.SlotDurationMilliseconds = 1000
params.OverrideBeaconConfig(cfg)
hook := logTest.NewGlobal()
ctrl := gomock.NewController(t)
@@ -247,7 +247,7 @@ func TestWaitForActivation_AttemptsReconnectionOnFailure(t *testing.T) {
params.SetupTestConfigCleanup(t)
cfg := params.MainnetConfig()
cfg.ConfigName = "test"
cfg.SecondsPerSlot = 1
cfg.SlotDurationMilliseconds = 1000
params.OverrideBeaconConfig(cfg)
ctrl := gomock.NewController(t)
defer ctrl.Finish()

View File

@@ -0,0 +1,65 @@
package client
import (
"context"
"time"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v7/monitoring/tracing"
"github.com/OffchainLabs/prysm/v7/monitoring/tracing/trace"
prysmTime "github.com/OffchainLabs/prysm/v7/time"
"github.com/OffchainLabs/prysm/v7/time/slots"
)
// slotComponentDeadline returns the absolute time corresponding to the provided slot component.
func (v *validator) slotComponentDeadline(slot primitives.Slot, component primitives.BP) (time.Time, error) {
startTime, err := slots.StartTime(v.genesisTime, slot)
if err != nil {
return time.Time{}, err
}
delay := params.BeaconConfig().SlotComponentDuration(component)
return startTime.Add(delay), nil
}
func (v *validator) waitUntilSlotComponent(ctx context.Context, slot primitives.Slot, component primitives.BP) {
ctx, span := trace.StartSpan(ctx, v.slotComponentSpanName(component))
defer span.End()
finalTime, err := v.slotComponentDeadline(slot, component)
if err != nil {
log.WithError(err).WithField("slot", slot).Error("Slot overflows, unable to wait for slot component deadline")
return
}
wait := prysmTime.Until(finalTime)
if wait <= 0 {
return
}
t := time.NewTimer(wait)
defer t.Stop()
select {
case <-ctx.Done():
tracing.AnnotateError(span, ctx.Err())
return
case <-t.C:
return
}
}
func (v *validator) slotComponentSpanName(component primitives.BP) string {
cfg := params.BeaconConfig()
switch component {
case cfg.AttestationDueBPS:
return "validator.waitAttestationWindow"
case cfg.AggregrateDueBPS:
return "validator.waitAggregateWindow"
case cfg.SyncMessageDueBPS:
return "validator.waitSyncMessageWindow"
case cfg.ContributionDueBPS:
return "validator.waitContributionWindow"
case cfg.ProposerReorgCutoffBPS:
return "validator.waitProposerReorgWindow"
default:
return "validator.waitSlotComponent"
}
}

View File

@@ -0,0 +1,87 @@
package client
import (
"context"
"testing"
"time"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v7/testing/assert"
"github.com/OffchainLabs/prysm/v7/testing/require"
"github.com/OffchainLabs/prysm/v7/time/slots"
)
func TestSlotComponentDeadline(t *testing.T) {
params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig()
v := &validator{genesisTime: time.Unix(1700000000, 0)}
slot := primitives.Slot(5)
component := cfg.AttestationDueBPS
got, err := v.slotComponentDeadline(slot, component)
require.NoError(t, err)
startTime, err := slots.StartTime(v.genesisTime, slot)
require.NoError(t, err)
expected := startTime.Add(cfg.SlotComponentDuration(component))
require.Equal(t, expected, got)
}
func TestSlotComponentSpanName(t *testing.T) {
params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig()
v := &validator{}
tests := []struct {
name string
component primitives.BP
expected string
}{
{
name: "attestation",
component: cfg.AttestationDueBPS,
expected: "validator.waitAttestationWindow",
},
{
name: "aggregate",
component: cfg.AggregrateDueBPS,
expected: "validator.waitAggregateWindow",
},
{
name: "default",
component: cfg.AttestationDueBPS + 7,
expected: "validator.waitSlotComponent",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.expected, v.slotComponentSpanName(tt.component))
})
}
}
func TestWaitUntilSlotComponent_ContextCancelReturnsImmediately(t *testing.T) {
params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig().Copy()
cfg.SlotDurationMilliseconds = 10000
params.OverrideBeaconConfig(cfg)
v := &validator{genesisTime: time.Now()}
ctx, cancel := context.WithCancel(context.Background())
cancel()
done := make(chan struct{})
go func() {
v.waitUntilSlotComponent(ctx, 1, cfg.AttestationDueBPS)
close(done)
}()
select {
case <-done:
case <-time.After(2 * time.Second):
t.Fatal("waitUntilSlotComponent did not return after context cancellation")
}
}