mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 13:58:09 -05:00
Compare commits
8 Commits
process-ex
...
lite-super
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93514608b0 | ||
|
|
f999173ccd | ||
|
|
9c074acf59 | ||
|
|
430bb09a74 | ||
|
|
d72ce136b8 | ||
|
|
2937b62a10 | ||
|
|
2fb2fecd92 | ||
|
|
f93a77aef9 |
@@ -471,10 +471,20 @@ func (s *Service) removeStartupState() {
|
||||
// It returns the (potentially updated) custody group count and the earliest available slot.
|
||||
func (s *Service) updateCustodyInfoInDB(slot primitives.Slot) (primitives.Slot, uint64, error) {
|
||||
isSubscribedToAllDataSubnets := flags.Get().SubscribeAllDataSubnets
|
||||
isLiteSupernode := flags.Get().LiteSupernode
|
||||
|
||||
cfg := params.BeaconConfig()
|
||||
custodyRequirement := cfg.CustodyRequirement
|
||||
|
||||
// Warn if both flags are set (supernode takes precedence).
|
||||
if isSubscribedToAllDataSubnets && isLiteSupernode {
|
||||
log.Warnf(
|
||||
"Both `--%s` and `--%s` flags are set. The supernode flag takes precedence.",
|
||||
flags.SubscribeAllDataSubnets.Name,
|
||||
flags.LiteSupernode.Name,
|
||||
)
|
||||
}
|
||||
|
||||
// Check if the node was previously subscribed to all data subnets, and if so,
|
||||
// store the new status accordingly.
|
||||
wasSubscribedToAllDataSubnets, err := s.cfg.BeaconDB.UpdateSubscribedToAllDataSubnets(s.ctx, isSubscribedToAllDataSubnets)
|
||||
@@ -490,11 +500,31 @@ func (s *Service) updateCustodyInfoInDB(slot primitives.Slot) (primitives.Slot,
|
||||
)
|
||||
}
|
||||
|
||||
// Check if the node was previously in lite-supernode mode, and if so,
|
||||
// store the new status accordingly.
|
||||
wasLiteSupernode, err := s.cfg.BeaconDB.UpdateLiteSupernode(s.ctx, isLiteSupernode)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not update lite-supernode status")
|
||||
}
|
||||
|
||||
// Warn the user if the node was previously in lite-supernode mode and is not any more.
|
||||
if wasLiteSupernode && !isLiteSupernode {
|
||||
log.Warnf(
|
||||
"Because the flag `--%s` was previously used, the node will remain in lite-supernode mode (subscribe to 64 subnets).",
|
||||
flags.LiteSupernode.Name,
|
||||
)
|
||||
}
|
||||
|
||||
// Compute the custody group count.
|
||||
// Note: Lite-supernode subscribes to 64 subnets (enough to reconstruct) but only custodies the minimum groups (4).
|
||||
// Only supernode increases custody to all 128 groups.
|
||||
// Persistence (preventing downgrades) is handled by UpdateCustodyInfo() which
|
||||
// refuses to decrease the stored custody count.
|
||||
custodyGroupCount := custodyRequirement
|
||||
if isSubscribedToAllDataSubnets {
|
||||
custodyGroupCount = cfg.NumberOfCustodyGroups
|
||||
}
|
||||
// Lite-supernode does NOT increase custody count - it keeps the minimum (4 or validator requirement).
|
||||
|
||||
// Safely compute the fulu fork slot.
|
||||
fuluForkSlot, err := fuluForkSlot()
|
||||
|
||||
@@ -129,6 +129,7 @@ type NoHeadAccessDatabase interface {
|
||||
|
||||
// Custody operations.
|
||||
UpdateSubscribedToAllDataSubnets(ctx context.Context, subscribed bool) (bool, error)
|
||||
UpdateLiteSupernode(ctx context.Context, enabled bool) (bool, error)
|
||||
UpdateCustodyInfo(ctx context.Context, earliestAvailableSlot primitives.Slot, custodyGroupCount uint64) (primitives.Slot, uint64, error)
|
||||
UpdateEarliestAvailableSlot(ctx context.Context, earliestAvailableSlot primitives.Slot) error
|
||||
|
||||
|
||||
@@ -203,3 +203,61 @@ func (s *Store) UpdateSubscribedToAllDataSubnets(ctx context.Context, subscribed
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// UpdateLiteSupernode updates the "lite-supernode" status in the database
|
||||
// only if `enabled` is `true`.
|
||||
// It returns the previous lite-supernode status.
|
||||
func (s *Store) UpdateLiteSupernode(ctx context.Context, enabled bool) (bool, error) {
|
||||
_, span := trace.StartSpan(ctx, "BeaconDB.UpdateLiteSupernode")
|
||||
defer span.End()
|
||||
|
||||
result := false
|
||||
if !enabled {
|
||||
if err := s.db.View(func(tx *bolt.Tx) error {
|
||||
// Retrieve the custody bucket.
|
||||
bucket := tx.Bucket(custodyBucket)
|
||||
if bucket == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Retrieve the lite-supernode flag.
|
||||
bytes := bucket.Get(liteSupernodeKey)
|
||||
if len(bytes) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if bytes[0] == 1 {
|
||||
result = true
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
if err := s.db.Update(func(tx *bolt.Tx) error {
|
||||
// Retrieve the custody bucket.
|
||||
bucket, err := tx.CreateBucketIfNotExists(custodyBucket)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "create custody bucket")
|
||||
}
|
||||
|
||||
bytes := bucket.Get(liteSupernodeKey)
|
||||
if len(bytes) != 0 && bytes[0] == 1 {
|
||||
result = true
|
||||
}
|
||||
|
||||
if err := bucket.Put(liteSupernodeKey, []byte{1}); err != nil {
|
||||
return errors.Wrap(err, "put lite-supernode")
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -67,6 +67,29 @@ func getSubscriptionStatusFromDB(t *testing.T, db *Store) bool {
|
||||
return subscribed
|
||||
}
|
||||
|
||||
// getLiteSupernodeStatusFromDB reads the lite-supernode status directly from the database for testing purposes.
|
||||
func getLiteSupernodeStatusFromDB(t *testing.T, db *Store) bool {
|
||||
t.Helper()
|
||||
var enabled bool
|
||||
|
||||
err := db.db.View(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket(custodyBucket)
|
||||
if bucket == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
bytes := bucket.Get(liteSupernodeKey)
|
||||
if len(bytes) != 0 && bytes[0] == 1 {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
return enabled
|
||||
}
|
||||
|
||||
func TestUpdateCustodyInfo(t *testing.T) {
|
||||
ctx := t.Context()
|
||||
|
||||
@@ -302,3 +325,57 @@ func TestUpdateSubscribedToAllDataSubnets(t *testing.T) {
|
||||
require.Equal(t, true, stored)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUpdateLiteSupernode(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
t.Run("initial update with empty database - set to false", func(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
|
||||
prev, err := db.UpdateLiteSupernode(ctx, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, prev)
|
||||
|
||||
stored := getLiteSupernodeStatusFromDB(t, db)
|
||||
require.Equal(t, false, stored)
|
||||
})
|
||||
|
||||
t.Run("initial update with empty database - set to true", func(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
|
||||
prev, err := db.UpdateLiteSupernode(ctx, true)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, prev)
|
||||
|
||||
stored := getLiteSupernodeStatusFromDB(t, db)
|
||||
require.Equal(t, true, stored)
|
||||
})
|
||||
|
||||
t.Run("attempt to update from true to false (should not change)", func(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
|
||||
_, err := db.UpdateLiteSupernode(ctx, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
prev, err := db.UpdateLiteSupernode(ctx, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, prev)
|
||||
|
||||
stored := getLiteSupernodeStatusFromDB(t, db)
|
||||
require.Equal(t, true, stored)
|
||||
})
|
||||
|
||||
t.Run("update from true to true (no change)", func(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
|
||||
_, err := db.UpdateLiteSupernode(ctx, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
prev, err := db.UpdateLiteSupernode(ctx, true)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, prev)
|
||||
|
||||
stored := getLiteSupernodeStatusFromDB(t, db)
|
||||
require.Equal(t, true, stored)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -77,4 +77,5 @@ var (
|
||||
groupCountKey = []byte("group-count")
|
||||
earliestAvailableSlotKey = []byte("earliest-available-slot")
|
||||
subscribeAllDataSubnetsKey = []byte("subscribe-all-data-subnets")
|
||||
liteSupernodeKey = []byte("lite-supernode")
|
||||
)
|
||||
|
||||
@@ -96,9 +96,12 @@ func (s *Service) updateCustodyInfoIfNeeded() error {
|
||||
|
||||
// custodyGroupCount computes the custody group count based on the custody requirement,
|
||||
// the validators custody requirement, and whether the node is subscribed to all data subnets.
|
||||
// Note: Lite-supernode subscribes to 64 subnets (enough to reconstruct) but only custodies the minimum groups.
|
||||
func (s *Service) custodyGroupCount(context.Context) (uint64, error) {
|
||||
cfg := params.BeaconConfig()
|
||||
|
||||
// Only supernode mode increases custody to all 128 groups.
|
||||
// Lite-supernode subscribes to 64 subnets but custodies the minimum.
|
||||
if flags.Get().SubscribeAllDataSubnets {
|
||||
return cfg.NumberOfCustodyGroups, nil
|
||||
}
|
||||
|
||||
@@ -697,10 +697,16 @@ func (s *Service) dataColumnSubnetIndices(primitives.Slot) map[uint64]bool {
|
||||
func (s *Service) samplingSize() (uint64, error) {
|
||||
cfg := params.BeaconConfig()
|
||||
|
||||
// Supernode subscribes to all subnets.
|
||||
if flags.Get().SubscribeAllDataSubnets {
|
||||
return cfg.DataColumnSidecarSubnetCount, nil
|
||||
}
|
||||
|
||||
// Lite-supernode subscribes to half (64 subnets - minimum needed to reconstruct).
|
||||
if flags.Get().LiteSupernode {
|
||||
return cfg.DataColumnSidecarSubnetCount / 2, nil
|
||||
}
|
||||
|
||||
// Compute the validators custody requirement.
|
||||
validatorsCustodyRequirement, err := s.validatorsCustodyRequirement()
|
||||
if err != nil {
|
||||
|
||||
2
changelog/james-prysm_lite-supernode.md
Normal file
2
changelog/james-prysm_lite-supernode.md
Normal file
@@ -0,0 +1,2 @@
|
||||
### Added
|
||||
- New flag `--lite-supernode` is an option to run the node with the minimum custody based on number of validators, but will subscribe to 64 subnets to obtain 64 data columns required to reconstruct all blobs.
|
||||
@@ -339,6 +339,13 @@ var (
|
||||
Aliases: []string{"subscribe-all-data-subnets"},
|
||||
Usage: "Enable subscription to all data subnets and store all blob columns, serving them over RPC. Required post-Fusaka for full blob reconstruction. This is effectively one-way: once enabled, the node keeps storing and serving all columns even if the flag is later unset.",
|
||||
}
|
||||
// LiteSupernode enables lite-supernode mode: subscribe to 64 subnets and store 64 columns (minimum for reconstruction),
|
||||
// but only custody/serve the minimum 4 groups to peers.
|
||||
LiteSupernode = &cli.BoolFlag{
|
||||
Name: "lite-supernode",
|
||||
Usage: "Enable lite-supernode mode: subscribe to 64 data column subnets (enough to reconstruct), " +
|
||||
"but only custody and serve the minimum 4 groups to peers. Once set, you can only upgrade to full supernode, not downgrade.",
|
||||
}
|
||||
// BatchVerifierLimit sets the maximum number of signatures to batch verify at once.
|
||||
BatchVerifierLimit = &cli.IntFlag{
|
||||
Name: "batch-verifier-limit",
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
type GlobalFlags struct {
|
||||
SubscribeToAllSubnets bool
|
||||
SubscribeAllDataSubnets bool
|
||||
LiteSupernode bool
|
||||
MinimumSyncPeers int
|
||||
MinimumPeersPerSubnet int
|
||||
MaxConcurrentDials int
|
||||
@@ -47,10 +48,15 @@ func ConfigureGlobalFlags(ctx *cli.Context) {
|
||||
}
|
||||
|
||||
if ctx.Bool(SubscribeAllDataSubnets.Name) {
|
||||
log.Warning("Subscribing to all data subnets")
|
||||
log.Warning("Subscribing to all data subnets (super-node mode: 128 custody groups)")
|
||||
cfg.SubscribeAllDataSubnets = true
|
||||
}
|
||||
|
||||
if ctx.Bool(LiteSupernode.Name) {
|
||||
log.Warning("Enabling lite-supernode mode (subscribe to 64 subnets, custody 4 groups)")
|
||||
cfg.LiteSupernode = true
|
||||
}
|
||||
|
||||
cfg.BlockBatchLimit = ctx.Int(BlockBatchLimit.Name)
|
||||
cfg.BlockBatchLimitBurstFactor = ctx.Int(BlockBatchLimitBurstFactor.Name)
|
||||
cfg.BlobBatchLimit = ctx.Int(BlobBatchLimit.Name)
|
||||
|
||||
@@ -66,6 +66,7 @@ var appFlags = []cli.Flag{
|
||||
flags.DisableDebugRPCEndpoints,
|
||||
flags.SubscribeToAllSubnets,
|
||||
flags.SubscribeAllDataSubnets,
|
||||
flags.LiteSupernode,
|
||||
flags.HistoricalSlasherNode,
|
||||
flags.ChainID,
|
||||
flags.NetworkID,
|
||||
|
||||
@@ -108,6 +108,7 @@ var appHelpFlagGroups = []flagGroup{
|
||||
flags.MinSyncPeers,
|
||||
flags.SubscribeToAllSubnets,
|
||||
flags.SubscribeAllDataSubnets,
|
||||
flags.LiteSupernode,
|
||||
},
|
||||
},
|
||||
{ // Flags relevant to storing data on disk and configuring the beacon chain database.
|
||||
|
||||
Reference in New Issue
Block a user