diff --git a/beacon-chain/light-client/store.go b/beacon-chain/light-client/store.go index 446c1622ae..177ec9b6e4 100644 --- a/beacon-chain/light-client/store.go +++ b/beacon-chain/light-client/store.go @@ -264,9 +264,11 @@ func (s *Store) SetLastFinalityUpdate(update interfaces.LightClientFinalityUpdat func (s *Store) setLastFinalityUpdate(update interfaces.LightClientFinalityUpdate, broadcast bool) { if broadcast && IsFinalityUpdateValidForBroadcast(update, s.lastFinalityUpdate) { - if err := s.p2p.BroadcastLightClientFinalityUpdate(context.Background(), update); err != nil { - log.WithError(err).Error("Could not broadcast light client finality update") - } + go func() { + if err := s.p2p.BroadcastLightClientFinalityUpdate(context.Background(), update); err != nil { + log.WithError(err).Error("Could not broadcast light client finality update") + } + }() } s.lastFinalityUpdate = update @@ -294,9 +296,11 @@ func (s *Store) SetLastOptimisticUpdate(update interfaces.LightClientOptimisticU func (s *Store) setLastOptimisticUpdate(update interfaces.LightClientOptimisticUpdate, broadcast bool) { if broadcast { - if err := s.p2p.BroadcastLightClientOptimisticUpdate(context.Background(), update); err != nil { - log.WithError(err).Error("Could not broadcast light client optimistic update") - } + go func() { + if err := s.p2p.BroadcastLightClientOptimisticUpdate(context.Background(), update); err != nil { + log.WithError(err).Error("Could not broadcast light client optimistic update") + } + }() } s.lastOptimisticUpdate = update diff --git a/beacon-chain/light-client/store_test.go b/beacon-chain/light-client/store_test.go index 7505749695..9808cd353d 100644 --- a/beacon-chain/light-client/store_test.go +++ b/beacon-chain/light-client/store_test.go @@ -3,6 +3,7 @@ package light_client import ( "context" "testing" + "time" "github.com/OffchainLabs/prysm/v6/async/event" "github.com/OffchainLabs/prysm/v6/beacon-chain/db" @@ -74,6 +75,7 @@ func TestLightClientStore_SetLastFinalityUpdate(t *testing.T) { p2p := p2pTesting.NewTestP2P(t) lcStore := NewLightClientStore(p2p, new(event.Feed), testDB.SetupDB(t)) + timeForGoroutinesToFinish := 20 * time.Microsecond // update 0 with basic data and no supermajority following an empty lastFinalityUpdate - should save and broadcast l0 := util.NewTestLightClient(t, version.Altair) update0, err := NewLightClientFinalityUpdateFromBeaconState(l0.Ctx, l0.State, l0.Block, l0.AttestedState, l0.AttestedBlock, l0.FinalizedBlock) @@ -85,6 +87,7 @@ func TestLightClientStore_SetLastFinalityUpdate(t *testing.T) { lcStore.SetLastFinalityUpdate(update0, true) require.Equal(t, update0, lcStore.LastFinalityUpdate(), "lastFinalityUpdate should match the set value") + time.Sleep(timeForGoroutinesToFinish) // give some time for the broadcast goroutine to finish require.Equal(t, true, p2p.BroadcastCalled.Load(), "Broadcast should have been called after setting a new last finality update when previous is nil") p2p.BroadcastCalled.Store(false) // Reset for next test @@ -99,6 +102,7 @@ func TestLightClientStore_SetLastFinalityUpdate(t *testing.T) { lcStore.SetLastFinalityUpdate(update1, true) require.Equal(t, update1, lcStore.LastFinalityUpdate(), "lastFinalityUpdate should match the set value") + time.Sleep(timeForGoroutinesToFinish) // give some time for the broadcast goroutine to finish require.Equal(t, false, p2p.BroadcastCalled.Load(), "Broadcast should not have been called after setting a new last finality update without supermajority") p2p.BroadcastCalled.Store(false) // Reset for next test @@ -113,6 +117,7 @@ func TestLightClientStore_SetLastFinalityUpdate(t *testing.T) { lcStore.SetLastFinalityUpdate(update2, true) require.Equal(t, update2, lcStore.LastFinalityUpdate(), "lastFinalityUpdate should match the set value") + time.Sleep(timeForGoroutinesToFinish) // give some time for the broadcast goroutine to finish require.Equal(t, true, p2p.BroadcastCalled.Load(), "Broadcast should have been called after setting a new last finality update with supermajority") p2p.BroadcastCalled.Store(false) // Reset for next test @@ -127,6 +132,7 @@ func TestLightClientStore_SetLastFinalityUpdate(t *testing.T) { lcStore.SetLastFinalityUpdate(update3, true) require.Equal(t, update3, lcStore.LastFinalityUpdate(), "lastFinalityUpdate should match the set value") + time.Sleep(timeForGoroutinesToFinish) // give some time for the broadcast goroutine to finish require.Equal(t, false, p2p.BroadcastCalled.Load(), "Broadcast should not have been when previous was already broadcast") // update 4 with increased finality slot, increased attested slot, and supermajority - should save and broadcast @@ -140,6 +146,7 @@ func TestLightClientStore_SetLastFinalityUpdate(t *testing.T) { lcStore.SetLastFinalityUpdate(update4, true) require.Equal(t, update4, lcStore.LastFinalityUpdate(), "lastFinalityUpdate should match the set value") + time.Sleep(timeForGoroutinesToFinish) // give some time for the broadcast goroutine to finish require.Equal(t, true, p2p.BroadcastCalled.Load(), "Broadcast should have been called after a new finality update with increased finality slot") p2p.BroadcastCalled.Store(false) // Reset for next test @@ -154,6 +161,7 @@ func TestLightClientStore_SetLastFinalityUpdate(t *testing.T) { lcStore.SetLastFinalityUpdate(update5, true) require.Equal(t, update5, lcStore.LastFinalityUpdate(), "lastFinalityUpdate should match the set value") + time.Sleep(timeForGoroutinesToFinish) // give some time for the broadcast goroutine to finish require.Equal(t, false, p2p.BroadcastCalled.Load(), "Broadcast should not have been called when previous was already broadcast with supermajority") // update 6 with the same new finality slot, increased attested slot, and no supermajority - should save but not broadcast @@ -167,6 +175,7 @@ func TestLightClientStore_SetLastFinalityUpdate(t *testing.T) { lcStore.SetLastFinalityUpdate(update6, true) require.Equal(t, update6, lcStore.LastFinalityUpdate(), "lastFinalityUpdate should match the set value") + time.Sleep(timeForGoroutinesToFinish) // give some time for the broadcast goroutine to finish require.Equal(t, false, p2p.BroadcastCalled.Load(), "Broadcast should not have been called when previous was already broadcast with supermajority") } diff --git a/beacon-chain/p2p/broadcaster.go b/beacon-chain/p2p/broadcaster.go index 329a582c8d..03b38e29ac 100644 --- a/beacon-chain/p2p/broadcaster.go +++ b/beacon-chain/p2p/broadcaster.go @@ -278,6 +278,20 @@ func (s *Service) BroadcastLightClientOptimisticUpdate(ctx context.Context, upda return errors.New("attempted to broadcast nil light client optimistic update") } + // add delay to ensure block has time to propagate + slotStart, err := slots.StartTime(s.genesisTime, update.SignatureSlot()) + if err != nil { + err := errors.Wrap(err, "could not compute slot start time") + tracing.AnnotateError(span, err) + return err + } + timeSinceSlotStart := time.Since(slotStart) + expectedDelay := slots.ComponentDuration(primitives.BP(params.BeaconConfig().SyncMessageDueBPS)) + if timeSinceSlotStart < expectedDelay { + waitDuration := expectedDelay - timeSinceSlotStart + <-time.After(waitDuration) + } + digest := params.ForkDigest(slots.ToEpoch(update.AttestedHeader().Beacon().Slot)) if err := s.broadcastObject(ctx, update, lcOptimisticToTopic(digest)); err != nil { log.WithError(err).Debug("Failed to broadcast light client optimistic update") @@ -298,6 +312,20 @@ func (s *Service) BroadcastLightClientFinalityUpdate(ctx context.Context, update return errors.New("attempted to broadcast nil light client finality update") } + // add delay to ensure block has time to propagate + slotStart, err := slots.StartTime(s.genesisTime, update.SignatureSlot()) + if err != nil { + err := errors.Wrap(err, "could not compute slot start time") + tracing.AnnotateError(span, err) + return err + } + timeSinceSlotStart := time.Since(slotStart) + expectedDelay := slots.ComponentDuration(primitives.BP(params.BeaconConfig().SyncMessageDueBPS)) + if timeSinceSlotStart < expectedDelay { + waitDuration := expectedDelay - timeSinceSlotStart + <-time.After(waitDuration) + } + forkDigest := params.ForkDigest(slots.ToEpoch(update.AttestedHeader().Beacon().Slot)) if err := s.broadcastObject(ctx, update, lcFinalityToTopic(forkDigest)); err != nil { log.WithError(err).Debug("Failed to broadcast light client finality update") diff --git a/beacon-chain/p2p/broadcaster_test.go b/beacon-chain/p2p/broadcaster_test.go index bdb509928e..36696b85e3 100644 --- a/beacon-chain/p2p/broadcaster_test.go +++ b/beacon-chain/p2p/broadcaster_test.go @@ -20,6 +20,7 @@ import ( "github.com/OffchainLabs/prysm/v6/config/params" "github.com/OffchainLabs/prysm/v6/consensus-types/blocks" "github.com/OffchainLabs/prysm/v6/consensus-types/interfaces" + "github.com/OffchainLabs/prysm/v6/consensus-types/primitives" "github.com/OffchainLabs/prysm/v6/consensus-types/wrapper" "github.com/OffchainLabs/prysm/v6/encoding/bytesutil" ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1" @@ -529,6 +530,11 @@ func TestService_BroadcastBlob(t *testing.T) { } func TestService_BroadcastLightClientOptimisticUpdate(t *testing.T) { + params.SetupTestConfigCleanup(t) + config := params.BeaconConfig().Copy() + config.SyncMessageDueBPS = 60 // ~72 millisecond + params.OverrideBeaconConfig(config) + p1 := p2ptest.NewTestP2P(t) p2 := p2ptest.NewTestP2P(t) p1.Connect(p2) @@ -539,7 +545,7 @@ func TestService_BroadcastLightClientOptimisticUpdate(t *testing.T) { pubsub: p1.PubSub(), joinedTopics: map[string]*pubsub.Topic{}, cfg: &Config{}, - genesisTime: time.Now(), + genesisTime: time.Now().Add(-33 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second), // the signature slot of the mock update is 33 genesisValidatorsRoot: bytesutil.PadTo([]byte{'A'}, 32), subnetsLock: make(map[uint64]*sync.RWMutex), subnetsLockLock: sync.Mutex{}, @@ -566,12 +572,19 @@ func TestService_BroadcastLightClientOptimisticUpdate(t *testing.T) { wg.Add(1) go func(tt *testing.T) { defer wg.Done() - ctx, cancel := context.WithTimeout(t.Context(), 1*time.Second) + ctx, cancel := context.WithTimeout(t.Context(), 150*time.Millisecond) defer cancel() incomingMessage, err := sub.Next(ctx) require.NoError(t, err) + slotStartTime, err := slots.StartTime(p.genesisTime, msg.SignatureSlot()) + require.NoError(t, err) + expectedDelay := slots.ComponentDuration(primitives.BP(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)) + } + result := ðpb.LightClientOptimisticUpdateAltair{} require.NoError(t, p.Encoding().DecodeGossip(incomingMessage.Data, result)) if !proto.Equal(result, msg.Proto()) { @@ -593,6 +606,11 @@ func TestService_BroadcastLightClientOptimisticUpdate(t *testing.T) { } func TestService_BroadcastLightClientFinalityUpdate(t *testing.T) { + params.SetupTestConfigCleanup(t) + config := params.BeaconConfig().Copy() + config.SyncMessageDueBPS = 60 // ~72 millisecond + params.OverrideBeaconConfig(config) + p1 := p2ptest.NewTestP2P(t) p2 := p2ptest.NewTestP2P(t) p1.Connect(p2) @@ -603,7 +621,7 @@ func TestService_BroadcastLightClientFinalityUpdate(t *testing.T) { pubsub: p1.PubSub(), joinedTopics: map[string]*pubsub.Topic{}, cfg: &Config{}, - genesisTime: time.Now(), + genesisTime: time.Now().Add(-33 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second), // the signature slot of the mock update is 33 genesisValidatorsRoot: bytesutil.PadTo([]byte{'A'}, 32), subnetsLock: make(map[uint64]*sync.RWMutex), subnetsLockLock: sync.Mutex{}, @@ -630,12 +648,19 @@ func TestService_BroadcastLightClientFinalityUpdate(t *testing.T) { wg.Add(1) go func(tt *testing.T) { defer wg.Done() - ctx, cancel := context.WithTimeout(t.Context(), 1*time.Second) + ctx, cancel := context.WithTimeout(t.Context(), 150*time.Millisecond) defer cancel() incomingMessage, err := sub.Next(ctx) require.NoError(t, err) + slotStartTime, err := slots.StartTime(p.genesisTime, msg.SignatureSlot()) + require.NoError(t, err) + expectedDelay := slots.ComponentDuration(primitives.BP(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)) + } + result := ðpb.LightClientFinalityUpdateAltair{} require.NoError(t, p.Encoding().DecodeGossip(incomingMessage.Data, result)) if !proto.Equal(result, msg.Proto()) { diff --git a/beacon-chain/rpc/eth/config/handlers_test.go b/beacon-chain/rpc/eth/config/handlers_test.go index c01cd066be..13c4fe69f8 100644 --- a/beacon-chain/rpc/eth/config/handlers_test.go +++ b/beacon-chain/rpc/eth/config/handlers_test.go @@ -164,6 +164,7 @@ func TestGetSpec(t *testing.T) { config.KzgCommitmentInclusionProofDepth = 101 config.BlobsidecarSubnetCount = 102 config.BlobsidecarSubnetCountElectra = 103 + config.SyncMessageDueBPS = 104 var dbp [4]byte copy(dbp[:], []byte{'0', '0', '0', '1'}) @@ -202,7 +203,7 @@ func TestGetSpec(t *testing.T) { data, ok := resp.Data.(map[string]interface{}) require.Equal(t, true, ok) - assert.Equal(t, 176, len(data)) + assert.Equal(t, 177, len(data)) for k, v := range data { t.Run(k, func(t *testing.T) { switch k { @@ -579,6 +580,8 @@ func TestGetSpec(t *testing.T) { assert.Equal(t, "102", v) case "BLOB_SIDECAR_SUBNET_COUNT_ELECTRA": assert.Equal(t, "103", v) + case "SYNC_MESSAGE_DUE_BPS": + assert.Equal(t, "104", v) case "BLOB_SCHEDULE": // BLOB_SCHEDULE should be an empty slice when no schedule is defined blobSchedule, ok := v.([]interface{}) diff --git a/beacon-chain/sync/validate_light_client.go b/beacon-chain/sync/validate_light_client.go index d0b89fbc45..31aa9cf9cb 100644 --- a/beacon-chain/sync/validate_light_client.go +++ b/beacon-chain/sync/validate_light_client.go @@ -3,10 +3,10 @@ package sync import ( "context" "fmt" - "time" "github.com/OffchainLabs/prysm/v6/config/params" "github.com/OffchainLabs/prysm/v6/consensus-types/interfaces" + "github.com/OffchainLabs/prysm/v6/consensus-types/primitives" "github.com/OffchainLabs/prysm/v6/monitoring/tracing" "github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace" "github.com/OffchainLabs/prysm/v6/time/slots" @@ -53,17 +53,14 @@ func (s *Service) validateLightClientOptimisticUpdate(ctx context.Context, pid p return pubsub.ValidationIgnore, err } - // [IGNORE] The optimistic_update is received after the block at signature_slot was given enough time - // to propagate through the network -- i.e. validate that one-third of optimistic_update.signature_slot - // has transpired (SECONDS_PER_SLOT / INTERVALS_PER_SLOT seconds after the start of the slot, - // with a MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance) + // validate that enough time has passed since the start of the slot so the block has had enough time to propagate slotStart, err := slots.StartTime(s.cfg.clock.GenesisTime(), newUpdate.SignatureSlot()) if err != nil { log.WithError(err).Debug("Peer sent a slot that would overflow slot start time") return pubsub.ValidationReject, nil } earliestValidTime := slotStart. - Add(time.Second * time.Duration(params.BeaconConfig().SecondsPerSlot/params.BeaconConfig().IntervalsPerSlot)). + Add(slots.ComponentDuration(primitives.BP(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") @@ -126,17 +123,14 @@ func (s *Service) validateLightClientFinalityUpdate(ctx context.Context, pid pee return pubsub.ValidationIgnore, err } - // [IGNORE] The optimistic_update is received after the block at signature_slot was given enough time - // to propagate through the network -- i.e. validate that one-third of optimistic_update.signature_slot - // has transpired (SECONDS_PER_SLOT / INTERVALS_PER_SLOT seconds after the start of the slot, - // with a MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance) + // validate that enough time has passed since the start of the slot so the block has had enough time to propagate slotStart, err := slots.StartTime(s.cfg.clock.GenesisTime(), newUpdate.SignatureSlot()) if err != nil { log.WithError(err).Debug("Peer sent a slot that would overflow slot start time") return pubsub.ValidationReject, nil } earliestValidTime := slotStart. - Add(time.Second * time.Duration(params.BeaconConfig().SecondsPerSlot/params.BeaconConfig().IntervalsPerSlot)). + Add(slots.ComponentDuration(primitives.BP(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") diff --git a/beacon-chain/sync/validate_light_client_test.go b/beacon-chain/sync/validate_light_client_test.go index 4ca2b1cf56..6e74234e6f 100644 --- a/beacon-chain/sync/validate_light_client_test.go +++ b/beacon-chain/sync/validate_light_client_test.go @@ -2,6 +2,7 @@ package sync import ( "bytes" + "math" "testing" "time" @@ -15,9 +16,11 @@ import ( mockSync "github.com/OffchainLabs/prysm/v6/beacon-chain/sync/initial-sync/testing" "github.com/OffchainLabs/prysm/v6/config/params" "github.com/OffchainLabs/prysm/v6/consensus-types/interfaces" + "github.com/OffchainLabs/prysm/v6/consensus-types/primitives" "github.com/OffchainLabs/prysm/v6/runtime/version" "github.com/OffchainLabs/prysm/v6/testing/require" "github.com/OffchainLabs/prysm/v6/testing/util" + "github.com/OffchainLabs/prysm/v6/time/slots" pubsub "github.com/libp2p/go-libp2p-pubsub" pb "github.com/libp2p/go-libp2p-pubsub/pb" ) @@ -80,7 +83,7 @@ func TestValidateLightClientOptimisticUpdate(t *testing.T) { }, { name: "not enough time passed", - genesisDrift: -secondsPerSlot / slotIntervals, + genesisDrift: -int(math.Ceil(float64(slots.ComponentDuration(primitives.BP(params.BeaconConfig().SyncMessageDueBPS))) / float64(time.Second))), oldUpdateOptions: []util.LightClientOption{}, newUpdateOptions: []util.LightClientOption{}, expectedResult: pubsub.ValidationIgnore, @@ -93,7 +96,6 @@ func TestValidateLightClientOptimisticUpdate(t *testing.T) { }, { name: "new update is different", - genesisDrift: secondsPerSlot, oldUpdateOptions: []util.LightClientOption{}, newUpdateOptions: []util.LightClientOption{util.WithIncreasedAttestedSlot(1)}, expectedResult: pubsub.ValidationIgnore, @@ -207,7 +209,7 @@ func TestValidateLightClientFinalityUpdate(t *testing.T) { }, { name: "not enough time passed", - genesisDrift: -secondsPerSlot / slotIntervals, + genesisDrift: -int(math.Ceil(float64(slots.ComponentDuration(primitives.BP(params.BeaconConfig().SyncMessageDueBPS))) / float64(time.Second))), oldUpdateOptions: []util.LightClientOption{}, newUpdateOptions: []util.LightClientOption{}, expectedResult: pubsub.ValidationIgnore, @@ -220,7 +222,6 @@ func TestValidateLightClientFinalityUpdate(t *testing.T) { }, { name: "new update is different", - genesisDrift: secondsPerSlot, oldUpdateOptions: []util.LightClientOption{}, newUpdateOptions: []util.LightClientOption{util.WithIncreasedFinalizedSlot(1)}, expectedResult: pubsub.ValidationIgnore, diff --git a/changelog/bastin_delayed-lc-broadcast.md b/changelog/bastin_delayed-lc-broadcast.md new file mode 100644 index 0000000000..71e5864c99 --- /dev/null +++ b/changelog/bastin_delayed-lc-broadcast.md @@ -0,0 +1,3 @@ +### Added + +- Added expected delay before broadcasting light client p2p messages. \ No newline at end of file diff --git a/config/params/BUILD.bazel b/config/params/BUILD.bazel index 85b09198c9..b1d325f443 100644 --- a/config/params/BUILD.bazel +++ b/config/params/BUILD.bazel @@ -3,6 +3,7 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", srcs = [ + "basis_points.go", "config.go", "config_utils_develop.go", # keep "config_utils_prod.go", diff --git a/config/params/basis_points.go b/config/params/basis_points.go new file mode 100644 index 0000000000..c2590bd397 --- /dev/null +++ b/config/params/basis_points.go @@ -0,0 +1,10 @@ +package params + +import "github.com/OffchainLabs/prysm/v6/consensus-types/primitives" + +const BasisPoints = primitives.BP(10000) + +// SlotBP returns the basis points for a given slot. +func SlotBP() primitives.BP { + return primitives.BP(12000) +} diff --git a/config/params/config.go b/config/params/config.go index 1821db1fb7..e0dc7d9476 100644 --- a/config/params/config.go +++ b/config/params/config.go @@ -223,6 +223,7 @@ 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. diff --git a/config/params/loader_test.go b/config/params/loader_test.go index 19831ca62e..b72cec3edb 100644 --- a/config/params/loader_test.go +++ b/config/params/loader_test.go @@ -64,7 +64,6 @@ var placeholderFields = []string{ "PROPOSER_SCORE_BOOST_EIP7732", "PROPOSER_SELECTION_GAP", "SLOT_DURATION_MS", - "SYNC_MESSAGE_DUE_BPS", "SYNC_MESSAGE_DUE_BPS_GLOAS", "TARGET_NUMBER_OF_PEERS", "UPDATE_TIMEOUT", @@ -102,6 +101,7 @@ 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.SyncMessageDueBPS, actual.SyncMessageDueBPS, "%s: SyncMessageDueBPS", name) // Validator params. assert.Equal(t, expected.Eth1FollowDistance, actual.Eth1FollowDistance, "%s: Eth1FollowDistance", name) diff --git a/config/params/mainnet_config.go b/config/params/mainnet_config.go index ea41c51ecb..2b55b40d82 100644 --- a/config/params/mainnet_config.go +++ b/config/params/mainnet_config.go @@ -257,6 +257,7 @@ var mainnetBeaconConfig = &BeaconChainConfig{ // Light client MinSyncCommitteeParticipants: 1, MaxRequestLightClientUpdates: 128, + SyncMessageDueBPS: 3333, // Bellatrix TerminalBlockHashActivationEpoch: 18446744073709551615, diff --git a/consensus-types/primitives/BUILD.bazel b/consensus-types/primitives/BUILD.bazel index 88b44859c9..f27023c2a6 100644 --- a/consensus-types/primitives/BUILD.bazel +++ b/consensus-types/primitives/BUILD.bazel @@ -3,6 +3,7 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", srcs = [ + "basis_points.go", "committee_bits_mainnet.go", "committee_bits_minimal.go", # keep "committee_index.go", diff --git a/consensus-types/primitives/basis_points.go b/consensus-types/primitives/basis_points.go new file mode 100644 index 0000000000..288c234bce --- /dev/null +++ b/consensus-types/primitives/basis_points.go @@ -0,0 +1,3 @@ +package primitives + +type BP uint64 diff --git a/time/slots/slottime.go b/time/slots/slottime.go index e48e715c19..f7cd983782 100644 --- a/time/slots/slottime.go +++ b/time/slots/slottime.go @@ -307,3 +307,9 @@ 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 +}