mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-08 04:54:05 -05:00
Use explicit slot component timing configs (#15999)
* Use new timing configs (due BPS) * Bastin's feedback
This commit is contained in:
@@ -16,11 +16,11 @@ import (
|
||||
|
||||
// testBlobSetup holds common test data for blob reconstruction tests.
|
||||
type testBlobSetup struct {
|
||||
blobCount int
|
||||
blobs []kzg.Blob
|
||||
roBlock blocks.ROBlock
|
||||
roDataColumnSidecars []blocks.RODataColumn
|
||||
verifiedRoDataColumnSidecars []blocks.VerifiedRODataColumn
|
||||
blobCount int
|
||||
blobs []kzg.Blob
|
||||
roBlock blocks.ROBlock
|
||||
roDataColumnSidecars []blocks.RODataColumn
|
||||
verifiedRoDataColumnSidecars []blocks.VerifiedRODataColumn
|
||||
}
|
||||
|
||||
// setupTestBlobs creates a complete test setup with blobs, cells, proofs, and data column sidecars.
|
||||
|
||||
@@ -146,7 +146,7 @@ func TestEnsureEmbeddedGenesis(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
// Embedded Genesis works with Mainnet config
|
||||
cfg := params.MainnetConfig()
|
||||
cfg.SecondsPerSlot = 1
|
||||
cfg.SlotDurationMilliseconds = 1000
|
||||
undo, err := params.SetActiveWithUndo(cfg)
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
|
||||
@@ -134,7 +134,7 @@ func (n *Node) setNodeAndParentValidated(ctx context.Context) error {
|
||||
// slot will have secs = 3 below.
|
||||
func (n *Node) arrivedEarly(genesis time.Time) (bool, error) {
|
||||
sss, err := slots.SinceSlotStart(n.slot, genesis, n.timestamp.Truncate(time.Second)) // Truncate such that 3.9999 seconds will have a value of 3.
|
||||
votingWindow := time.Duration(params.BeaconConfig().SecondsPerSlot/params.BeaconConfig().IntervalsPerSlot) * time.Second
|
||||
votingWindow := params.BeaconConfig().SlotComponentDuration(params.BeaconConfig().AttestationDueBPS)
|
||||
return sss < votingWindow, err
|
||||
}
|
||||
|
||||
|
||||
@@ -134,8 +134,8 @@ func TestForkChoice_GetProposerHead(t *testing.T) {
|
||||
headRoot, err := f.Head(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, blk.Root(), headRoot)
|
||||
orphanLateBlockFirstThreshold := params.BeaconConfig().SecondsPerSlot / params.BeaconConfig().IntervalsPerSlot
|
||||
f.store.headNode.timestamp.Add(-1 * time.Duration(params.BeaconConfig().SecondsPerSlot-orphanLateBlockFirstThreshold) * time.Second)
|
||||
orphanLateBlockFirstThreshold := params.BeaconConfig().SlotComponentDuration(params.BeaconConfig().AttestationDueBPS)
|
||||
f.store.headNode.timestamp.Add(-1 * (params.BeaconConfig().SlotDuration() - orphanLateBlockFirstThreshold))
|
||||
t.Run("head is weak", func(t *testing.T) {
|
||||
require.Equal(t, parentRoot, f.GetProposerHead())
|
||||
})
|
||||
|
||||
@@ -137,7 +137,7 @@ func (s *Store) insert(ctx context.Context,
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not determine time since current slot started: %w", err)
|
||||
}
|
||||
boostThreshold := time.Duration(params.BeaconConfig().SecondsPerSlot/params.BeaconConfig().IntervalsPerSlot) * time.Second
|
||||
boostThreshold := params.BeaconConfig().SlotComponentDuration(params.BeaconConfig().AttestationDueBPS)
|
||||
isFirstBlock := s.proposerBoostRoot == [32]byte{}
|
||||
if currentSlot == slot && sss < boostThreshold && isFirstBlock {
|
||||
s.proposerBoostRoot = root
|
||||
|
||||
@@ -286,7 +286,7 @@ func (s *Service) BroadcastLightClientOptimisticUpdate(ctx context.Context, upda
|
||||
return err
|
||||
}
|
||||
timeSinceSlotStart := time.Since(slotStart)
|
||||
expectedDelay := slots.ComponentDuration(primitives.BP(params.BeaconConfig().SyncMessageDueBPS))
|
||||
expectedDelay := params.BeaconConfig().SlotComponentDuration(params.BeaconConfig().SyncMessageDueBPS)
|
||||
if timeSinceSlotStart < expectedDelay {
|
||||
waitDuration := expectedDelay - timeSinceSlotStart
|
||||
<-time.After(waitDuration)
|
||||
@@ -320,7 +320,7 @@ func (s *Service) BroadcastLightClientFinalityUpdate(ctx context.Context, update
|
||||
return err
|
||||
}
|
||||
timeSinceSlotStart := time.Since(slotStart)
|
||||
expectedDelay := slots.ComponentDuration(primitives.BP(params.BeaconConfig().SyncMessageDueBPS))
|
||||
expectedDelay := params.BeaconConfig().SlotComponentDuration(params.BeaconConfig().SyncMessageDueBPS)
|
||||
if timeSinceSlotStart < expectedDelay {
|
||||
waitDuration := expectedDelay - timeSinceSlotStart
|
||||
<-time.After(waitDuration)
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/wrapper"
|
||||
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
@@ -598,7 +597,7 @@ func TestService_BroadcastLightClientOptimisticUpdate(t *testing.T) {
|
||||
|
||||
slotStartTime, err := slots.StartTime(p.genesisTime, msg.SignatureSlot())
|
||||
require.NoError(t, err)
|
||||
expectedDelay := slots.ComponentDuration(primitives.BP(params.BeaconConfig().SyncMessageDueBPS))
|
||||
expectedDelay := params.BeaconConfig().SlotComponentDuration(params.BeaconConfig().SyncMessageDueBPS)
|
||||
if time.Now().Before(slotStartTime.Add(expectedDelay)) {
|
||||
tt.Errorf("Message received too early, now %v, expected at least %v", time.Now(), slotStartTime.Add(expectedDelay))
|
||||
}
|
||||
@@ -674,7 +673,7 @@ func TestService_BroadcastLightClientFinalityUpdate(t *testing.T) {
|
||||
|
||||
slotStartTime, err := slots.StartTime(p.genesisTime, msg.SignatureSlot())
|
||||
require.NoError(t, err)
|
||||
expectedDelay := slots.ComponentDuration(primitives.BP(params.BeaconConfig().SyncMessageDueBPS))
|
||||
expectedDelay := params.BeaconConfig().SlotComponentDuration(params.BeaconConfig().SyncMessageDueBPS)
|
||||
if time.Now().Before(slotStartTime.Add(expectedDelay)) {
|
||||
tt.Errorf("Message received too early, now %v, expected at least %v", time.Now(), slotStartTime.Add(expectedDelay))
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ func TestService_Start_NoDiscoverFlag(t *testing.T) {
|
||||
beaconCfg.AltairForkEpoch = 0
|
||||
beaconCfg.BellatrixForkEpoch = 0
|
||||
beaconCfg.CapellaForkEpoch = 0
|
||||
beaconCfg.SecondsPerSlot = 1
|
||||
beaconCfg.SlotDurationMilliseconds = 1000
|
||||
params.OverrideBeaconConfig(beaconCfg)
|
||||
|
||||
exitRoutine := make(chan bool)
|
||||
|
||||
@@ -87,6 +87,7 @@ func TestGetSpec(t *testing.T) {
|
||||
config.ETH1AddressWithdrawalPrefixByte = byte('c')
|
||||
config.GenesisDelay = 24
|
||||
config.SecondsPerSlot = 25
|
||||
config.SlotDurationMilliseconds = 120
|
||||
config.MinAttestationInclusionDelay = 26
|
||||
config.SlotsPerEpoch = 27
|
||||
config.MinSeedLookahead = 28
|
||||
@@ -129,6 +130,10 @@ func TestGetSpec(t *testing.T) {
|
||||
config.ProportionalSlashingMultiplierAltair = 69
|
||||
config.InactivityScoreRecoveryRate = 70
|
||||
config.MinSyncCommitteeParticipants = 71
|
||||
config.ProposerReorgCutoffBPS = primitives.BP(121)
|
||||
config.AttestationDueBPS = primitives.BP(122)
|
||||
config.AggregrateDueBPS = primitives.BP(123)
|
||||
config.ContributionDueBPS = primitives.BP(124)
|
||||
config.TerminalBlockHash = common.HexToHash("TerminalBlockHash")
|
||||
config.TerminalBlockHashActivationEpoch = 72
|
||||
config.TerminalTotalDifficulty = "73"
|
||||
@@ -201,7 +206,7 @@ func TestGetSpec(t *testing.T) {
|
||||
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), &resp))
|
||||
data, ok := resp.Data.(map[string]interface{})
|
||||
require.Equal(t, true, ok)
|
||||
assert.Equal(t, 171, len(data))
|
||||
assert.Equal(t, 176, len(data))
|
||||
for k, v := range data {
|
||||
t.Run(k, func(t *testing.T) {
|
||||
switch k {
|
||||
@@ -291,6 +296,8 @@ func TestGetSpec(t *testing.T) {
|
||||
assert.Equal(t, "24", v)
|
||||
case "SECONDS_PER_SLOT":
|
||||
assert.Equal(t, "25", v)
|
||||
case "SLOT_DURATION_MS":
|
||||
assert.Equal(t, "120", v)
|
||||
case "MIN_ATTESTATION_INCLUSION_DELAY":
|
||||
assert.Equal(t, "26", v)
|
||||
case "SLOTS_PER_EPOCH":
|
||||
@@ -447,6 +454,14 @@ func TestGetSpec(t *testing.T) {
|
||||
assert.Equal(t, "20", v)
|
||||
case "REORG_PARENT_WEIGHT_THRESHOLD":
|
||||
assert.Equal(t, "160", v)
|
||||
case "PROPOSER_REORG_CUTOFF_BPS":
|
||||
assert.Equal(t, "121", v)
|
||||
case "ATTESTATION_DUE_BPS":
|
||||
assert.Equal(t, "122", v)
|
||||
case "AGGREGRATE_DUE_BPS":
|
||||
assert.Equal(t, "123", v)
|
||||
case "CONTRIBUTION_DUE_BPS":
|
||||
assert.Equal(t, "124", v)
|
||||
case "MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT":
|
||||
assert.Equal(t, "8", v)
|
||||
case "MAX_REQUEST_LIGHT_CLIENT_UPDATES":
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
func TestGoodByeRPCHandler_Disconnects_With_Peer(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.MainnetConfig()
|
||||
cfg.SecondsPerSlot = 1
|
||||
cfg.SlotDurationMilliseconds = 1000
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
p1 := p2ptest.NewTestP2P(t)
|
||||
|
||||
@@ -130,7 +130,7 @@ func TestSubscribe_UnsubscribeTopic(t *testing.T) {
|
||||
func TestSubscribe_ReceivesAttesterSlashing(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.MainnetConfig()
|
||||
cfg.SecondsPerSlot = 1
|
||||
cfg.SlotDurationMilliseconds = 1000
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
p2pService := p2ptest.NewTestP2P(t)
|
||||
@@ -443,7 +443,7 @@ func Test_wrapAndReportValidation(t *testing.T) {
|
||||
func TestFilterSubnetPeers(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.MainnetConfig()
|
||||
cfg.SecondsPerSlot = 1
|
||||
cfg.SlotDurationMilliseconds = 1000
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
gFlags := new(flags.GlobalFlags)
|
||||
@@ -457,8 +457,9 @@ func TestFilterSubnetPeers(t *testing.T) {
|
||||
currSlot := primitives.Slot(100)
|
||||
|
||||
gt := time.Now()
|
||||
slotDuration := params.BeaconConfig().SlotDuration()
|
||||
genPlus100 := func() time.Time {
|
||||
return gt.Add(time.Second * time.Duration(uint64(currSlot)*params.BeaconConfig().SecondsPerSlot))
|
||||
return gt.Add(time.Duration(uint64(currSlot)) * slotDuration)
|
||||
}
|
||||
chain := &mockChain.ChainService{
|
||||
Genesis: gt,
|
||||
@@ -525,7 +526,7 @@ func TestFilterSubnetPeers(t *testing.T) {
|
||||
func TestSubscribeWithSyncSubnets_DynamicOK(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.MainnetConfig()
|
||||
cfg.SecondsPerSlot = 1
|
||||
cfg.SlotDurationMilliseconds = 1000
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
p := p2ptest.NewTestP2P(t)
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
"github.com/OffchainLabs/prysm/v7/monitoring/tracing"
|
||||
"github.com/OffchainLabs/prysm/v7/monitoring/tracing/trace"
|
||||
"github.com/OffchainLabs/prysm/v7/time/slots"
|
||||
@@ -60,7 +59,7 @@ func (s *Service) validateLightClientOptimisticUpdate(ctx context.Context, pid p
|
||||
return pubsub.ValidationReject, nil
|
||||
}
|
||||
earliestValidTime := slotStart.
|
||||
Add(slots.ComponentDuration(primitives.BP(params.BeaconConfig().SyncMessageDueBPS))).
|
||||
Add(params.BeaconConfig().SlotComponentDuration(params.BeaconConfig().SyncMessageDueBPS)).
|
||||
Add(-params.BeaconConfig().MaximumGossipClockDisparityDuration())
|
||||
if s.cfg.clock.Now().Before(earliestValidTime) {
|
||||
log.Debug("Newly received light client optimistic update ignored. not enough time passed for block to propagate")
|
||||
@@ -130,7 +129,7 @@ func (s *Service) validateLightClientFinalityUpdate(ctx context.Context, pid pee
|
||||
return pubsub.ValidationReject, nil
|
||||
}
|
||||
earliestValidTime := slotStart.
|
||||
Add(slots.ComponentDuration(primitives.BP(params.BeaconConfig().SyncMessageDueBPS))).
|
||||
Add(params.BeaconConfig().SlotComponentDuration(params.BeaconConfig().SyncMessageDueBPS)).
|
||||
Add(-params.BeaconConfig().MaximumGossipClockDisparityDuration())
|
||||
if s.cfg.clock.Now().Before(earliestValidTime) {
|
||||
log.Debug("Newly received light client finality update ignored. not enough time passed for block to propagate")
|
||||
|
||||
@@ -16,11 +16,9 @@ import (
|
||||
mockSync "github.com/OffchainLabs/prysm/v7/beacon-chain/sync/initial-sync/testing"
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/util"
|
||||
"github.com/OffchainLabs/prysm/v7/time/slots"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
pb "github.com/libp2p/go-libp2p-pubsub/pb"
|
||||
)
|
||||
@@ -83,7 +81,7 @@ func TestValidateLightClientOptimisticUpdate(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "not enough time passed",
|
||||
genesisDrift: -int(math.Ceil(float64(slots.ComponentDuration(primitives.BP(params.BeaconConfig().SyncMessageDueBPS))) / float64(time.Second))),
|
||||
genesisDrift: -int(math.Ceil(float64(params.BeaconConfig().SlotComponentDuration(params.BeaconConfig().SyncMessageDueBPS)) / float64(time.Second))),
|
||||
oldUpdateOptions: []util.LightClientOption{},
|
||||
newUpdateOptions: []util.LightClientOption{},
|
||||
expectedResult: pubsub.ValidationIgnore,
|
||||
@@ -209,7 +207,7 @@ func TestValidateLightClientFinalityUpdate(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "not enough time passed",
|
||||
genesisDrift: -int(math.Ceil(float64(slots.ComponentDuration(primitives.BP(params.BeaconConfig().SyncMessageDueBPS))) / float64(time.Second))),
|
||||
genesisDrift: -int(math.Ceil(float64(params.BeaconConfig().SlotComponentDuration(params.BeaconConfig().SyncMessageDueBPS)) / float64(time.Second))),
|
||||
oldUpdateOptions: []util.LightClientOption{},
|
||||
newUpdateOptions: []util.LightClientOption{},
|
||||
expectedResult: pubsub.ValidationIgnore,
|
||||
|
||||
3
changelog/ttsao_use-timing-configs.md
Normal file
3
changelog/ttsao_use-timing-configs.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Changed
|
||||
|
||||
- Use explicit slot component timing configs
|
||||
@@ -4,7 +4,7 @@ import "github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
|
||||
const BasisPoints = primitives.BP(10000)
|
||||
|
||||
// SlotBP returns the basis points for a given slot.
|
||||
// SlotBP returns the duration of a slot expressed in milliseconds, represented as basis points of a slot.
|
||||
func SlotBP() primitives.BP {
|
||||
return primitives.BP(12000)
|
||||
return primitives.BP(BeaconConfig().SlotDurationMillis())
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ type BeaconChainConfig struct {
|
||||
GenesisDelay uint64 `yaml:"GENESIS_DELAY" spec:"true"` // GenesisDelay is the minimum number of seconds to delay starting the Ethereum Beacon Chain genesis. Must be at least 1 second.
|
||||
MinAttestationInclusionDelay primitives.Slot `yaml:"MIN_ATTESTATION_INCLUSION_DELAY" spec:"true"` // MinAttestationInclusionDelay defines how many slots validator has to wait to include attestation for beacon block.
|
||||
SecondsPerSlot uint64 `yaml:"SECONDS_PER_SLOT" spec:"true"` // SecondsPerSlot is how many seconds are in a single slot.
|
||||
SlotDurationMilliseconds uint64 `yaml:"SLOT_DURATION_MS" spec:"true"` // SlotDurationMilliseconds is the slot time expressed in milliseconds.
|
||||
SlotsPerEpoch primitives.Slot `yaml:"SLOTS_PER_EPOCH" spec:"true"` // SlotsPerEpoch is the number of slots in an epoch.
|
||||
SqrRootSlotsPerEpoch primitives.Slot // SqrRootSlotsPerEpoch is a hard coded value where we take the square root of `SlotsPerEpoch` and round down.
|
||||
MinSeedLookahead primitives.Epoch `yaml:"MIN_SEED_LOOKAHEAD" spec:"true"` // MinSeedLookahead is the duration of randao look ahead seed.
|
||||
@@ -84,6 +85,11 @@ type BeaconChainConfig struct {
|
||||
ReorgParentWeightThreshold uint64 `yaml:"REORG_PARENT_WEIGHT_THRESHOLD" spec:"true"` // ReorgParentWeightThreshold defines a value that is a % of the committee weight to consider a parent block strong and subject its child to being orphaned.
|
||||
ReorgMaxEpochsSinceFinalization primitives.Epoch `yaml:"REORG_MAX_EPOCHS_SINCE_FINALIZATION" spec:"true"` // This defines a limit to consider safe to orphan a block if the network is finalizing
|
||||
IntervalsPerSlot uint64 `yaml:"INTERVALS_PER_SLOT"` // IntervalsPerSlot defines the number of fork choice intervals in a slot defined in the fork choice spec.
|
||||
ProposerReorgCutoffBPS primitives.BP `yaml:"PROPOSER_REORG_CUTOFF_BPS" spec:"true"` // ProposerReorgCutoffBPS defines the proposer reorg deadline in basis points of the slot.
|
||||
AttestationDueBPS primitives.BP `yaml:"ATTESTATION_DUE_BPS" spec:"true"` // AttestationDueBPS defines the attestation due time in basis points of the slot.
|
||||
AggregrateDueBPS primitives.BP `yaml:"AGGREGRATE_DUE_BPS" spec:"true"` // AggregrateDueBPS defines the aggregate due time in basis points of the slot.
|
||||
SyncMessageDueBPS primitives.BP `yaml:"SYNC_MESSAGE_DUE_BPS" spec:"true"` // SyncMessageDueBPS defines the sync message due time in basis points of the slot.
|
||||
ContributionDueBPS primitives.BP `yaml:"CONTRIBUTION_DUE_BPS" spec:"true"` // ContributionDueBPS defines the contribution due time in basis points of the slot.
|
||||
|
||||
// Ethereum PoW parameters.
|
||||
DepositChainID uint64 `yaml:"DEPOSIT_CHAIN_ID" spec:"true"` // DepositChainID of the eth1 network. This used for replay protection.
|
||||
@@ -221,7 +227,6 @@ type BeaconChainConfig struct {
|
||||
// Light client
|
||||
MinSyncCommitteeParticipants uint64 `yaml:"MIN_SYNC_COMMITTEE_PARTICIPANTS" spec:"true"` // MinSyncCommitteeParticipants defines the minimum amount of sync committee participants for which the light client acknowledges the signature.
|
||||
MaxRequestLightClientUpdates uint64 `yaml:"MAX_REQUEST_LIGHT_CLIENT_UPDATES" spec:"true"` // MaxRequestLightClientUpdates defines the maximum amount of light client updates that can be requested in a single request.
|
||||
SyncMessageDueBPS uint64 `yaml:"SYNC_MESSAGE_DUE_BPS" spec:"true"` // SyncMessageDueBPS defines the due time for a sync message.
|
||||
|
||||
// Bellatrix
|
||||
TerminalBlockHash common.Hash `yaml:"TERMINAL_BLOCK_HASH" spec:"true"` // TerminalBlockHash of beacon chain.
|
||||
@@ -741,10 +746,29 @@ func SlotsForEpochs(count primitives.Epoch, b *BeaconChainConfig) primitives.Slo
|
||||
|
||||
// SlotsDuration returns the time duration of the given number of slots.
|
||||
func SlotsDuration(count primitives.Slot, b *BeaconChainConfig) time.Duration {
|
||||
return time.Duration(count) * SecondsPerSlot(b)
|
||||
return time.Duration(count) * b.SlotDuration()
|
||||
}
|
||||
|
||||
// SecondsPerSlot returns the time duration of a single slot.
|
||||
func SecondsPerSlot(b *BeaconChainConfig) time.Duration {
|
||||
return time.Duration(b.SecondsPerSlot) * time.Second
|
||||
return b.SlotDuration()
|
||||
}
|
||||
|
||||
// SlotDuration returns the configured slot duration as a time.Duration.
|
||||
func (b *BeaconChainConfig) SlotDuration() time.Duration {
|
||||
return time.Duration(b.SlotDurationMillis()) * time.Millisecond
|
||||
}
|
||||
|
||||
// SlotDurationMillis returns the configured slot duration in milliseconds.
|
||||
func (b *BeaconChainConfig) SlotDurationMillis() uint64 {
|
||||
if b.SlotDurationMilliseconds > 0 {
|
||||
return b.SlotDurationMilliseconds
|
||||
}
|
||||
return b.SecondsPerSlot * 1000
|
||||
}
|
||||
|
||||
// SlotComponentDuration returns the duration representing the given portion (in basis points) of a slot.
|
||||
func (b *BeaconChainConfig) SlotComponentDuration(bp primitives.BP) time.Duration {
|
||||
ms := uint64(bp) * b.SlotDurationMillis() / uint64(BasisPoints)
|
||||
return time.Duration(ms) * time.Millisecond
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"math"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
@@ -202,6 +203,127 @@ func fillGVR(value byte) [32]byte {
|
||||
return gvr
|
||||
}
|
||||
|
||||
func TestBeaconChainConfigSlotDuration(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
cfg params.BeaconChainConfig
|
||||
want time.Duration
|
||||
}{
|
||||
{
|
||||
name: "explicit duration",
|
||||
cfg: params.BeaconChainConfig{SlotDurationMilliseconds: 12_000},
|
||||
want: 12 * time.Second,
|
||||
},
|
||||
{
|
||||
name: "fallback to seconds per slot",
|
||||
cfg: params.BeaconChainConfig{SecondsPerSlot: 8},
|
||||
want: 8 * time.Second,
|
||||
},
|
||||
{
|
||||
name: "milliseconds override seconds per slot",
|
||||
cfg: params.BeaconChainConfig{
|
||||
SlotDurationMilliseconds: 7_000,
|
||||
SecondsPerSlot: 4,
|
||||
},
|
||||
want: 7 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.Equal(t, tt.want, tt.cfg.SlotDuration())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBeaconChainConfigSlotDurationMillis(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
cfg params.BeaconChainConfig
|
||||
want uint64
|
||||
}{
|
||||
{
|
||||
name: "uses slot duration milliseconds when set",
|
||||
cfg: params.BeaconChainConfig{SlotDurationMilliseconds: 4_800},
|
||||
want: 4_800,
|
||||
},
|
||||
{
|
||||
name: "derives from seconds per slot when unset",
|
||||
cfg: params.BeaconChainConfig{SecondsPerSlot: 6},
|
||||
want: 6_000,
|
||||
},
|
||||
{
|
||||
name: "returns zero when no duration configured",
|
||||
cfg: params.BeaconChainConfig{},
|
||||
want: 0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.Equal(t, tt.want, tt.cfg.SlotDurationMillis())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBeaconChainConfigSlotComponentDuration(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
cfg params.BeaconChainConfig
|
||||
bp primitives.BP
|
||||
want time.Duration
|
||||
}{
|
||||
{
|
||||
name: "zero basis points produces zero duration",
|
||||
cfg: params.BeaconChainConfig{SlotDurationMilliseconds: 12_000},
|
||||
bp: 0,
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "full slot basis points matches slot duration",
|
||||
cfg: params.BeaconChainConfig{SlotDurationMilliseconds: 12_000},
|
||||
bp: params.BasisPoints,
|
||||
want: 12 * time.Second,
|
||||
},
|
||||
{
|
||||
name: "quarter slot with explicit milliseconds",
|
||||
cfg: params.BeaconChainConfig{SlotDurationMilliseconds: 12_000},
|
||||
bp: params.BasisPoints / 4,
|
||||
want: 3 * time.Second,
|
||||
},
|
||||
{
|
||||
name: "fractional slot rounds down",
|
||||
cfg: params.BeaconChainConfig{SlotDurationMilliseconds: 1_001},
|
||||
bp: params.BasisPoints / 3,
|
||||
want: 333 * time.Millisecond,
|
||||
},
|
||||
{
|
||||
name: "uses seconds per slot fallback",
|
||||
cfg: params.BeaconChainConfig{SecondsPerSlot: 9},
|
||||
bp: params.BasisPoints / 2,
|
||||
want: 4500 * time.Millisecond,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.Equal(t, tt.want, tt.cfg.SlotComponentDuration(tt.bp))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEntryWithForkDigest(t *testing.T) {
|
||||
var zero [32]byte
|
||||
one := fillGVR(byte(1))
|
||||
|
||||
@@ -102,6 +102,7 @@ func compareConfigs(t *testing.T, expected, actual *BeaconChainConfig) {
|
||||
require.DeepEqual(t, expected.GenesisDelay, actual.GenesisDelay)
|
||||
require.DeepEqual(t, expected.MinAttestationInclusionDelay, actual.MinAttestationInclusionDelay)
|
||||
require.DeepEqual(t, expected.SecondsPerSlot, actual.SecondsPerSlot)
|
||||
require.DeepEqual(t, expected.SlotDurationMilliseconds, actual.SlotDurationMilliseconds)
|
||||
require.DeepEqual(t, expected.SlotsPerEpoch, actual.SlotsPerEpoch)
|
||||
require.DeepEqual(t, expected.SqrRootSlotsPerEpoch, actual.SqrRootSlotsPerEpoch)
|
||||
require.DeepEqual(t, expected.MinSeedLookahead, actual.MinSeedLookahead)
|
||||
|
||||
@@ -187,6 +187,7 @@ func ConfigToYaml(cfg *BeaconChainConfig) []byte {
|
||||
fmt.Sprintf("GENESIS_FORK_VERSION: %#x", cfg.GenesisForkVersion),
|
||||
fmt.Sprintf("CHURN_LIMIT_QUOTIENT: %d", cfg.ChurnLimitQuotient),
|
||||
fmt.Sprintf("SECONDS_PER_SLOT: %d", cfg.SecondsPerSlot),
|
||||
fmt.Sprintf("SLOT_DURATION_MS: %d", cfg.SlotDurationMilliseconds),
|
||||
fmt.Sprintf("SLOTS_PER_EPOCH: %d", cfg.SlotsPerEpoch),
|
||||
fmt.Sprintf("SECONDS_PER_ETH1_BLOCK: %d", cfg.SecondsPerETH1Block),
|
||||
fmt.Sprintf("ETH1_FOLLOW_DISTANCE: %d", cfg.Eth1FollowDistance),
|
||||
@@ -241,6 +242,11 @@ func ConfigToYaml(cfg *BeaconChainConfig) []byte {
|
||||
fmt.Sprintf("MIN_EPOCHS_FOR_BLOCK_REQUESTS: %d", int(cfg.MinEpochsForBlockRequests)),
|
||||
fmt.Sprintf("MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: %d", cfg.MinPerEpochChurnLimitElectra),
|
||||
fmt.Sprintf("MAX_BLOBS_PER_BLOCK: %d", cfg.DeprecatedMaxBlobsPerBlock),
|
||||
fmt.Sprintf("PROPOSER_REORG_CUTOFF_BPS: %d", cfg.ProposerReorgCutoffBPS),
|
||||
fmt.Sprintf("ATTESTATION_DUE_BPS: %d", cfg.AttestationDueBPS),
|
||||
fmt.Sprintf("AGGREGRATE_DUE_BPS: %d", cfg.AggregrateDueBPS),
|
||||
fmt.Sprintf("SYNC_MESSAGE_DUE_BPS: %d", cfg.SyncMessageDueBPS),
|
||||
fmt.Sprintf("CONTRIBUTION_DUE_BPS: %d", cfg.ContributionDueBPS),
|
||||
}
|
||||
|
||||
if len(cfg.BlobSchedule) > 0 {
|
||||
|
||||
@@ -27,11 +27,9 @@ var placeholderFields = []string{
|
||||
"AGGREGATE_DUE_BPS",
|
||||
"AGGREGATE_DUE_BPS_GLOAS",
|
||||
"ATTESTATION_DEADLINE",
|
||||
"ATTESTATION_DUE_BPS",
|
||||
"ATTESTATION_DUE_BPS_GLOAS",
|
||||
"BLOB_SIDECAR_SUBNET_COUNT_FULU",
|
||||
"CELLS_PER_EXT_BLOB",
|
||||
"CONTRIBUTION_DUE_BPS",
|
||||
"CONTRIBUTION_DUE_BPS_GLOAS",
|
||||
"EIP6110_FORK_EPOCH",
|
||||
"EIP6110_FORK_VERSION",
|
||||
@@ -60,10 +58,7 @@ var placeholderFields = []string{
|
||||
"PAYLOAD_ATTESTATION_DUE_BPS",
|
||||
"PROPOSER_INCLUSION_LIST_CUTOFF",
|
||||
"PROPOSER_INCLUSION_LIST_CUTOFF_BPS",
|
||||
"PROPOSER_REORG_CUTOFF_BPS",
|
||||
"PROPOSER_SCORE_BOOST_EIP7732",
|
||||
"PROPOSER_SELECTION_GAP",
|
||||
"SLOT_DURATION_MS",
|
||||
"SYNC_MESSAGE_DUE_BPS_GLOAS",
|
||||
"TARGET_NUMBER_OF_PEERS",
|
||||
"UPDATE_TIMEOUT",
|
||||
@@ -101,6 +96,10 @@ func assertEqualConfigs(t *testing.T, name string, fields []string, expected, ac
|
||||
assert.Equal(t, expected.HysteresisQuotient, actual.HysteresisQuotient, "%s: HysteresisQuotient", name)
|
||||
assert.Equal(t, expected.HysteresisDownwardMultiplier, actual.HysteresisDownwardMultiplier, "%s: HysteresisDownwardMultiplier", name)
|
||||
assert.Equal(t, expected.HysteresisUpwardMultiplier, actual.HysteresisUpwardMultiplier, "%s: HysteresisUpwardMultiplier", name)
|
||||
assert.Equal(t, expected.AttestationDueBPS, actual.AttestationDueBPS, "%s: AttestationDueBPS", name)
|
||||
assert.Equal(t, expected.AggregrateDueBPS, actual.AggregrateDueBPS, "%s: AggregrateDueBPS", name)
|
||||
assert.Equal(t, expected.ContributionDueBPS, actual.ContributionDueBPS, "%s: ContributionDueBPS", name)
|
||||
assert.Equal(t, expected.ProposerReorgCutoffBPS, actual.ProposerReorgCutoffBPS, "%s: ProposerReorgCutoffBPS", name)
|
||||
assert.Equal(t, expected.SyncMessageDueBPS, actual.SyncMessageDueBPS, "%s: SyncMessageDueBPS", name)
|
||||
|
||||
// Validator params.
|
||||
@@ -129,6 +128,7 @@ func assertEqualConfigs(t *testing.T, name string, fields []string, expected, ac
|
||||
// Time parameters.
|
||||
assert.Equal(t, expected.GenesisDelay, actual.GenesisDelay, "%s: GenesisDelay", name)
|
||||
assert.Equal(t, expected.SecondsPerSlot, actual.SecondsPerSlot, "%s: SecondsPerSlot", name)
|
||||
assert.Equal(t, expected.SlotDurationMilliseconds, actual.SlotDurationMilliseconds, "%s: SlotDurationMilliseconds", name)
|
||||
assert.Equal(t, expected.MinAttestationInclusionDelay, actual.MinAttestationInclusionDelay, "%s: MinAttestationInclusionDelay", name)
|
||||
assert.Equal(t, expected.SlotsPerEpoch, actual.SlotsPerEpoch, "%s: SlotsPerEpoch", name)
|
||||
assert.Equal(t, expected.MinSeedLookahead, actual.MinSeedLookahead, "%s: MinSeedLookahead", name)
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
|
||||
)
|
||||
|
||||
@@ -98,6 +99,7 @@ var mainnetBeaconConfig = &BeaconChainConfig{
|
||||
// Time parameter constants.
|
||||
MinAttestationInclusionDelay: 1,
|
||||
SecondsPerSlot: 12,
|
||||
SlotDurationMilliseconds: 12000,
|
||||
SlotsPerEpoch: 32,
|
||||
SqrRootSlotsPerEpoch: 5,
|
||||
MinSeedLookahead: 1,
|
||||
@@ -116,6 +118,13 @@ var mainnetBeaconConfig = &BeaconChainConfig{
|
||||
ReorgMaxEpochsSinceFinalization: 2,
|
||||
IntervalsPerSlot: 3,
|
||||
|
||||
// Time-based protocol parameters.
|
||||
ProposerReorgCutoffBPS: primitives.BP(1667),
|
||||
AttestationDueBPS: primitives.BP(3333),
|
||||
AggregrateDueBPS: primitives.BP(6667),
|
||||
SyncMessageDueBPS: primitives.BP(3333),
|
||||
ContributionDueBPS: primitives.BP(6667),
|
||||
|
||||
// Ethereum PoW parameters.
|
||||
DepositChainID: 1, // Chain ID of eth1 mainnet.
|
||||
DepositNetworkID: 1, // Network ID of eth1 mainnet.
|
||||
@@ -257,7 +266,6 @@ var mainnetBeaconConfig = &BeaconChainConfig{
|
||||
// Light client
|
||||
MinSyncCommitteeParticipants: 1,
|
||||
MaxRequestLightClientUpdates: 128,
|
||||
SyncMessageDueBPS: 3333,
|
||||
|
||||
// Bellatrix
|
||||
TerminalBlockHashActivationEpoch: 18446744073709551615,
|
||||
|
||||
@@ -34,6 +34,7 @@ func MinimalSpecConfig() *BeaconChainConfig {
|
||||
|
||||
// Time parameters
|
||||
minimalConfig.SecondsPerSlot = 6
|
||||
minimalConfig.SlotDurationMilliseconds = 6000
|
||||
minimalConfig.MinAttestationInclusionDelay = 1
|
||||
minimalConfig.SlotsPerEpoch = 8
|
||||
minimalConfig.SqrRootSlotsPerEpoch = 2
|
||||
|
||||
4
config/params/testdata/e2e_config.yaml
vendored
4
config/params/testdata/e2e_config.yaml
vendored
@@ -56,6 +56,8 @@ FULU_FORK_EPOCH: 18446744073709551615
|
||||
# ---------------------------------------------------------------
|
||||
# [customized] Faster for testing purposes
|
||||
SECONDS_PER_SLOT: 10 # Override for e2e tests
|
||||
# 10000 milliseconds, 10 seconds
|
||||
SLOT_DURATION_MS: 10000
|
||||
# 14 (estimate from Eth1 mainnet)
|
||||
SECONDS_PER_ETH1_BLOCK: 2 # Override for e2e tests
|
||||
# [customized] faster time for withdrawals
|
||||
@@ -133,4 +135,4 @@ BLOB_SCHEDULE:
|
||||
MAX_BLOBS_PER_BLOCK: 6
|
||||
# Electra
|
||||
- EPOCH: 14
|
||||
MAX_BLOBS_PER_BLOCK: 9
|
||||
MAX_BLOBS_PER_BLOCK: 9
|
||||
|
||||
@@ -58,6 +58,7 @@ func compareConfigs(t *testing.T, expected, actual *params.BeaconChainConfig) {
|
||||
require.DeepEqual(t, expected.GenesisDelay, actual.GenesisDelay)
|
||||
require.DeepEqual(t, expected.MinAttestationInclusionDelay, actual.MinAttestationInclusionDelay)
|
||||
require.DeepEqual(t, expected.SecondsPerSlot, actual.SecondsPerSlot)
|
||||
require.DeepEqual(t, expected.SlotDurationMilliseconds, actual.SlotDurationMilliseconds)
|
||||
require.DeepEqual(t, expected.SlotsPerEpoch, actual.SlotsPerEpoch)
|
||||
require.DeepEqual(t, expected.SqrRootSlotsPerEpoch, actual.SqrRootSlotsPerEpoch)
|
||||
require.DeepEqual(t, expected.MinSeedLookahead, actual.MinSeedLookahead)
|
||||
|
||||
@@ -27,6 +27,7 @@ func E2ETestConfig() *BeaconChainConfig {
|
||||
|
||||
// Time parameters.
|
||||
e2eConfig.SecondsPerSlot = 10
|
||||
e2eConfig.SlotDurationMilliseconds = 10000
|
||||
e2eConfig.SlotsPerEpoch = 6
|
||||
e2eConfig.SqrRootSlotsPerEpoch = 2
|
||||
e2eConfig.SecondsPerETH1Block = 2
|
||||
@@ -81,6 +82,7 @@ func E2EMainnetTestConfig() *BeaconChainConfig {
|
||||
|
||||
// Time parameters.
|
||||
e2eConfig.SecondsPerSlot = 6
|
||||
e2eConfig.SlotDurationMilliseconds = 6000
|
||||
e2eConfig.SqrRootSlotsPerEpoch = 5
|
||||
e2eConfig.SecondsPerETH1Block = 2
|
||||
e2eConfig.ShardCommitteePeriod = 4
|
||||
|
||||
@@ -40,14 +40,17 @@ func EpochsSinceGenesis(genesis time.Time) primitives.Epoch {
|
||||
// in milliseconds, useful for dividing values such as 1 second into
|
||||
// millisecond-based durations.
|
||||
func DivideSlotBy(timesPerSlot int64) time.Duration {
|
||||
return time.Duration(int64(params.BeaconConfig().SecondsPerSlot*1000)/timesPerSlot) * time.Millisecond
|
||||
if timesPerSlot == 0 {
|
||||
return 0
|
||||
}
|
||||
return params.BeaconConfig().SlotDuration() / time.Duration(timesPerSlot)
|
||||
}
|
||||
|
||||
// MultiplySlotBy multiplies the SECONDS_PER_SLOT configuration
|
||||
// parameter by a specified number. It returns a value of time.Duration
|
||||
// in millisecond-based durations.
|
||||
func MultiplySlotBy(times int64) time.Duration {
|
||||
return time.Duration(int64(params.BeaconConfig().SecondsPerSlot)*times) * time.Second
|
||||
return params.BeaconConfig().SlotDuration() * time.Duration(times)
|
||||
}
|
||||
|
||||
// AbsoluteValueSlotDifference between two slots.
|
||||
@@ -175,12 +178,11 @@ func VerifyTime(genesis time.Time, slot primitives.Slot, timeTolerance time.Dura
|
||||
// StartTime takes the given slot and genesis time to determine the start time of the slot.
|
||||
// This method returns an error if the product of the slot duration * slot overflows int64.
|
||||
func StartTime(genesis time.Time, slot primitives.Slot) (time.Time, error) {
|
||||
_, err := slot.SafeMul(params.BeaconConfig().SecondsPerSlot)
|
||||
ms, err := slot.SafeMul(params.BeaconConfig().SlotDurationMillis())
|
||||
if err != nil {
|
||||
return time.Unix(0, 0), fmt.Errorf("slot (%d) is in the far distant future: %w", slot, err)
|
||||
}
|
||||
sd := time.Second * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Duration(slot)
|
||||
return genesis.Add(sd), nil
|
||||
return genesis.Add(time.Duration(ms) * time.Millisecond), nil
|
||||
}
|
||||
|
||||
// CurrentSlot returns the current slot as determined by the local clock and
|
||||
@@ -194,7 +196,7 @@ func At(genesis, tm time.Time) primitives.Slot {
|
||||
if tm.Before(genesis) {
|
||||
return 0
|
||||
}
|
||||
return primitives.Slot(tm.Sub(genesis) / time.Second / time.Duration(params.BeaconConfig().SecondsPerSlot))
|
||||
return primitives.Slot(tm.Sub(genesis) / params.BeaconConfig().SlotDuration())
|
||||
}
|
||||
|
||||
// Duration computes the span of time between two instants, represented as Slots.
|
||||
@@ -202,7 +204,7 @@ func Duration(start, end time.Time) primitives.Slot {
|
||||
if end.Before(start) {
|
||||
return 0
|
||||
}
|
||||
return primitives.Slot(uint64(end.Unix()-start.Unix()) / params.BeaconConfig().SecondsPerSlot)
|
||||
return primitives.Slot((end.Sub(start)) / params.BeaconConfig().SlotDuration())
|
||||
}
|
||||
|
||||
// ValidateClock validates a provided slot against the local
|
||||
@@ -231,7 +233,7 @@ func RoundUpToNearestEpoch(slot primitives.Slot) primitives.Slot {
|
||||
// depending on the provided genesis and current slot.
|
||||
func VotingPeriodStartTime(genesis uint64, slot primitives.Slot) uint64 {
|
||||
slots := params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().EpochsPerEth1VotingPeriod))
|
||||
startTime := uint64((slot - slot.ModSlot(slots)).Mul(params.BeaconConfig().SecondsPerSlot))
|
||||
startTime := uint64((slot - slot.ModSlot(slots)).Mul(params.BeaconConfig().SlotDurationMillis())) / 1000
|
||||
return genesis + startTime
|
||||
}
|
||||
|
||||
@@ -267,7 +269,7 @@ func SyncCommitteePeriodStartEpoch(e primitives.Epoch) (primitives.Epoch, error)
|
||||
// given slot start time. This method returns an error if the timestamp happens
|
||||
// before the given slot start time.
|
||||
func SinceSlotStart(s primitives.Slot, genesis time.Time, timestamp time.Time) (time.Duration, error) {
|
||||
limit := genesis.Add(time.Duration(uint64(s)*params.BeaconConfig().SecondsPerSlot) * time.Second)
|
||||
limit := genesis.Add(time.Duration(uint64(s)) * params.BeaconConfig().SlotDuration())
|
||||
if timestamp.Before(limit) {
|
||||
return 0, fmt.Errorf("could not compute seconds since slot %d start: invalid timestamp, got %s < want %s", s, timestamp, limit)
|
||||
}
|
||||
@@ -277,8 +279,8 @@ func SinceSlotStart(s primitives.Slot, genesis time.Time, timestamp time.Time) (
|
||||
// WithinVotingWindow returns whether the current time is within the voting window
|
||||
// (eg. 4 seconds on mainnet) of the current slot.
|
||||
func WithinVotingWindow(genesis time.Time, slot primitives.Slot) bool {
|
||||
votingWindow := params.BeaconConfig().SecondsPerSlot / params.BeaconConfig().IntervalsPerSlot
|
||||
return time.Since(UnsafeStartTime(genesis, slot)) < time.Duration(votingWindow)*time.Second
|
||||
votingWindow := params.BeaconConfig().SlotComponentDuration(params.BeaconConfig().AttestationDueBPS)
|
||||
return time.Since(UnsafeStartTime(genesis, slot)) < votingWindow
|
||||
}
|
||||
|
||||
// MaxSafeEpoch gives the largest epoch value that can be safely converted to a slot.
|
||||
@@ -307,9 +309,3 @@ func SecondsUntilNextEpochStart(genesis time.Time) (uint64, error) {
|
||||
}).Debugf("%d seconds until next epoch", waitTime)
|
||||
return waitTime, nil
|
||||
}
|
||||
|
||||
// ComponentDuration calculates the duration of a slot component in milliseconds.
|
||||
func ComponentDuration(component primitives.BP) time.Duration {
|
||||
ms := (component * params.SlotBP()) / params.BasisPoints
|
||||
return time.Duration(ms) * time.Millisecond
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
|
||||
65
validator/client/wait_helpers.go
Normal file
65
validator/client/wait_helpers.go
Normal 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"
|
||||
}
|
||||
}
|
||||
87
validator/client/wait_helpers_test.go
Normal file
87
validator/client/wait_helpers_test.go
Normal 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")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user