Support New Subnet Backbone (#13179)

* add in changes

* fix it up

* fix test

* gaz

* lint

* add back

* fix tests

* fix it

* fix tests

* add lib

* fix it
This commit is contained in:
Nishant Das
2023-12-08 12:07:48 +08:00
committed by GitHub
parent 68b7d1009e
commit 590317553c
20 changed files with 188 additions and 127 deletions

View File

@@ -24,6 +24,8 @@ type subnetIDs struct {
// SubnetIDs for attester and aggregator.
var SubnetIDs = newSubnetIDs()
var subnetKey = "persistent-subnets"
func newSubnetIDs() *subnetIDs {
// Given a node can calculate committee assignments of current epoch and next epoch.
// Max size is set to 2 epoch length.
@@ -91,11 +93,11 @@ func (s *subnetIDs) GetAggregatorSubnetIDs(slot primitives.Slot) []uint64 {
// GetPersistentSubnets retrieves the persistent subnet and expiration time of that validator's
// subscription.
func (s *subnetIDs) GetPersistentSubnets(pubkey []byte) ([]uint64, bool, time.Time) {
func (s *subnetIDs) GetPersistentSubnets() ([]uint64, bool, time.Time) {
s.subnetsLock.RLock()
defer s.subnetsLock.RUnlock()
id, duration, ok := s.persistentSubnets.GetWithExpiration(string(pubkey))
id, duration, ok := s.persistentSubnets.GetWithExpiration(subnetKey)
if !ok {
return []uint64{}, ok, time.Time{}
}
@@ -122,11 +124,11 @@ func (s *subnetIDs) GetAllSubnets() []uint64 {
// AddPersistentCommittee adds the relevant committee for that particular validator along with its
// expiration period.
func (s *subnetIDs) AddPersistentCommittee(pubkey []byte, comIndex []uint64, duration time.Duration) {
func (s *subnetIDs) AddPersistentCommittee(comIndex []uint64, duration time.Duration) {
s.subnetsLock.Lock()
defer s.subnetsLock.Unlock()
s.persistentSubnets.Set(string(pubkey), comIndex, duration)
s.persistentSubnets.Set(subnetKey, comIndex, duration)
}
// EmptyAllCaches empties out all the related caches and flushes any stored

View File

@@ -3,10 +3,8 @@ package cache
import (
"testing"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/testing/assert"
"github.com/prysmaticlabs/prysm/v4/testing/require"
)
func TestSubnetIDsCache_RoundTrip(t *testing.T) {
@@ -46,21 +44,8 @@ func TestSubnetIDsCache_RoundTrip(t *testing.T) {
func TestSubnetIDsCache_PersistentCommitteeRoundtrip(t *testing.T) {
c := newSubnetIDs()
for i := 0; i < 20; i++ {
pubkey := [fieldparams.BLSPubkeyLength]byte{byte(i)}
c.AddPersistentCommittee(pubkey[:], []uint64{uint64(i)}, 0)
}
c.AddPersistentCommittee([]uint64{0, 1, 2, 7, 8}, 0)
for i := uint64(0); i < 20; i++ {
pubkey := [fieldparams.BLSPubkeyLength]byte{byte(i)}
idxs, ok, _ := c.GetPersistentSubnets(pubkey[:])
if !ok {
t.Errorf("Couldn't find entry in cache for pubkey %#x", pubkey)
continue
}
require.Equal(t, i, idxs[0])
}
coms := c.GetAllSubnets()
assert.Equal(t, 20, len(coms))
assert.Equal(t, 5, len(coms))
}

View File

@@ -77,6 +77,7 @@ go_library(
"@com_github_ethereum_go_ethereum//p2p/discover:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/enode:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/enr:go_default_library",
"@com_github_holiman_uint256//:go_default_library",
"@com_github_kr_pretty//:go_default_library",
"@com_github_libp2p_go_libp2p//:go_default_library",
"@com_github_libp2p_go_libp2p//config:go_default_library",
@@ -164,6 +165,7 @@ go_test(
"//testing/require:go_default_library",
"//testing/util:go_default_library",
"//time:go_default_library",
"//time/slots:go_default_library",
"@com_github_ethereum_go_ethereum//crypto:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/discover:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/enode:go_default_library",

View File

@@ -42,6 +42,12 @@ func (s *Service) RefreshENR() {
if s.dv5Listener == nil || !s.isInitialized() {
return
}
currEpoch := slots.ToEpoch(slots.CurrentSlot(uint64(s.genesisTime.Unix())))
if err := initializePersistentSubnets(s.dv5Listener.LocalNode().ID(), currEpoch); err != nil {
log.WithError(err).Error("Could not initialize persistent subnets")
return
}
bitV := bitfield.NewBitvector64()
committees := cache.SubnetIDs.GetAllSubnets()
for _, idx := range committees {
@@ -52,8 +58,8 @@ func (s *Service) RefreshENR() {
log.WithError(err).Error("Could not retrieve att bitfield")
return
}
// Compare current epoch with our fork epochs
currEpoch := slots.ToEpoch(slots.CurrentSlot(uint64(s.genesisTime.Unix())))
altairForkEpoch := params.BeaconConfig().AltairForkEpoch
switch {
// Altair Behaviour

View File

@@ -36,6 +36,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/runtime/version"
"github.com/prysmaticlabs/prysm/v4/testing/assert"
"github.com/prysmaticlabs/prysm/v4/testing/require"
"github.com/prysmaticlabs/prysm/v4/time/slots"
logTest "github.com/sirupsen/logrus/hooks/test"
)
@@ -364,7 +365,15 @@ func TestRefreshENR_ForkBoundaries(t *testing.T) {
return s
},
postValidation: func(t *testing.T, s *Service) {
assert.DeepEqual(t, bitfield.NewBitvector64(), s.metaData.AttnetsBitfield())
currEpoch := slots.ToEpoch(slots.CurrentSlot(uint64(s.genesisTime.Unix())))
subs, err := computeSubscribedSubnets(s.dv5Listener.LocalNode().ID(), currEpoch)
assert.NoError(t, err)
bitV := bitfield.NewBitvector64()
for _, idx := range subs {
bitV.SetBitAt(idx, true)
}
assert.DeepEqual(t, bitV, s.metaData.AttnetsBitfield())
},
},
{
@@ -382,7 +391,7 @@ func TestRefreshENR_ForkBoundaries(t *testing.T) {
s.dv5Listener = listener
s.metaData = wrapper.WrappedMetadataV0(new(ethpb.MetaDataV0))
s.updateSubnetRecordWithMetadata([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01})
cache.SubnetIDs.AddPersistentCommittee([]byte{'A'}, []uint64{1, 2, 3, 23}, 0)
cache.SubnetIDs.AddPersistentCommittee([]uint64{1, 2, 3, 23}, 0)
return s
},
postValidation: func(t *testing.T, s *Service) {
@@ -411,7 +420,7 @@ func TestRefreshENR_ForkBoundaries(t *testing.T) {
s.dv5Listener = listener
s.metaData = wrapper.WrappedMetadataV0(new(ethpb.MetaDataV0))
s.updateSubnetRecordWithMetadata([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01})
cache.SubnetIDs.AddPersistentCommittee([]byte{'A'}, []uint64{1, 2, 3, 23}, 0)
cache.SubnetIDs.AddPersistentCommittee([]uint64{1, 2, 3, 23}, 0)
return s
},
postValidation: func(t *testing.T, s *Service) {
@@ -447,7 +456,15 @@ func TestRefreshENR_ForkBoundaries(t *testing.T) {
postValidation: func(t *testing.T, s *Service) {
assert.Equal(t, version.Altair, s.metaData.Version())
assert.DeepEqual(t, bitfield.Bitvector4{0x00}, s.metaData.MetadataObjV1().Syncnets)
assert.DeepEqual(t, bitfield.Bitvector64{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, s.metaData.AttnetsBitfield())
currEpoch := slots.ToEpoch(slots.CurrentSlot(uint64(s.genesisTime.Unix())))
subs, err := computeSubscribedSubnets(s.dv5Listener.LocalNode().ID(), currEpoch)
assert.NoError(t, err)
bitV := bitfield.NewBitvector64()
for _, idx := range subs {
bitV.SetBitAt(idx, true)
}
assert.DeepEqual(t, bitV, s.metaData.AttnetsBitfield())
},
},
{
@@ -472,7 +489,7 @@ func TestRefreshENR_ForkBoundaries(t *testing.T) {
s.dv5Listener = listener
s.metaData = wrapper.WrappedMetadataV0(new(ethpb.MetaDataV0))
s.updateSubnetRecordWithMetadata([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
cache.SubnetIDs.AddPersistentCommittee([]byte{'A'}, []uint64{1, 2, 3, 23}, 0)
cache.SubnetIDs.AddPersistentCommittee([]uint64{1, 2, 3, 23}, 0)
cache.SyncSubnetIDs.AddSyncCommitteeSubnets([]byte{'A'}, 0, []uint64{0, 1}, 0)
return s
},

View File

@@ -4,13 +4,20 @@ import (
"context"
"strings"
"sync"
"time"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
"github.com/holiman/uint256"
"github.com/pkg/errors"
"github.com/prysmaticlabs/go-bitfield"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v4/cmd/beacon-chain/flags"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/consensus-types/wrapper"
"github.com/prysmaticlabs/prysm/v4/crypto/hash"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
mathutil "github.com/prysmaticlabs/prysm/v4/math"
"go.opencensus.io/trace"
@@ -178,6 +185,82 @@ func (s *Service) updateSubnetRecordWithMetadataV2(bitVAtt bitfield.Bitvector64,
})
}
func initializePersistentSubnets(id enode.ID, epoch primitives.Epoch) error {
_, ok, expTime := cache.SubnetIDs.GetPersistentSubnets()
if ok && expTime.After(time.Now()) {
return nil
}
subs, err := computeSubscribedSubnets(id, epoch)
if err != nil {
return err
}
newExpTime := computeSubscriptionExpirationTime(id, epoch)
cache.SubnetIDs.AddPersistentCommittee(subs, newExpTime)
return nil
}
// Spec pseudocode definition:
//
// def compute_subscribed_subnets(node_id: NodeID, epoch: Epoch) -> Sequence[SubnetID]:
//
// return [compute_subscribed_subnet(node_id, epoch, index) for index in range(SUBNETS_PER_NODE)]
func computeSubscribedSubnets(nodeID enode.ID, epoch primitives.Epoch) ([]uint64, error) {
subs := []uint64{}
for i := uint64(0); i < params.BeaconConfig().SubnetsPerNode; i++ {
sub, err := computeSubscribedSubnet(nodeID, epoch, i)
if err != nil {
return nil, err
}
subs = append(subs, sub)
}
return subs, nil
}
// Spec pseudocode definition:
//
// def compute_subscribed_subnet(node_id: NodeID, epoch: Epoch, index: int) -> SubnetID:
//
// node_id_prefix = node_id >> (NODE_ID_BITS - ATTESTATION_SUBNET_PREFIX_BITS)
// node_offset = node_id % EPOCHS_PER_SUBNET_SUBSCRIPTION
// permutation_seed = hash(uint_to_bytes(uint64((epoch + node_offset) // EPOCHS_PER_SUBNET_SUBSCRIPTION)))
// permutated_prefix = compute_shuffled_index(
// node_id_prefix,
// 1 << ATTESTATION_SUBNET_PREFIX_BITS,
// permutation_seed,
// )
// return SubnetID((permutated_prefix + index) % ATTESTATION_SUBNET_COUNT)
func computeSubscribedSubnet(nodeID enode.ID, epoch primitives.Epoch, index uint64) (uint64, error) {
nodeOffset, nodeIdPrefix := computeOffsetAndPrefix(nodeID)
seedInput := (nodeOffset + uint64(epoch)) / params.BeaconConfig().EpochsPerSubnetSubscription
permSeed := hash.Hash(bytesutil.Bytes8(seedInput))
permutatedPrefix, err := helpers.ComputeShuffledIndex(primitives.ValidatorIndex(nodeIdPrefix), 1<<params.BeaconConfig().AttestationSubnetPrefixBits, permSeed, true)
if err != nil {
return 0, err
}
subnet := (uint64(permutatedPrefix) + index) % params.BeaconNetworkConfig().AttestationSubnetCount
return subnet, nil
}
func computeSubscriptionExpirationTime(nodeID enode.ID, epoch primitives.Epoch) time.Duration {
nodeOffset, _ := computeOffsetAndPrefix(nodeID)
pastEpochs := (nodeOffset + uint64(epoch)) % params.BeaconConfig().EpochsPerSubnetSubscription
remEpochs := params.BeaconConfig().EpochsPerSubnetSubscription - pastEpochs
epochDuration := time.Duration(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().SecondsPerSlot))
epochTime := time.Duration(remEpochs) * epochDuration
return epochTime * time.Second
}
func computeOffsetAndPrefix(nodeID enode.ID) (uint64, uint64) {
num := uint256.NewInt(0).SetBytes(nodeID.Bytes())
remBits := params.BeaconConfig().NodeIdBits - params.BeaconConfig().AttestationSubnetPrefixBits
// Number of bits left will be representable by a uint64 value.
nodeIdPrefix := num.Rsh(num, uint(remBits)).Uint64()
// Reinitialize big int.
num = uint256.NewInt(0).SetBytes(nodeID.Bytes())
nodeOffset := num.Mod(num, uint256.NewInt(params.BeaconConfig().EpochsPerSubnetSubscription)).Uint64()
return nodeOffset, nodeIdPrefix
}
// Initializes a bitvector of attestation subnets beacon nodes is subscribed to
// and creates a new ENR entry with its default value.
func initializeAttSubnets(node *enode.LocalNode) *enode.LocalNode {

View File

@@ -488,3 +488,38 @@ func Test_SyncSubnets(t *testing.T) {
})
}
}
func TestSubnetComputation(t *testing.T) {
db, err := enode.OpenDB("")
assert.NoError(t, err)
defer db.Close()
priv, _, err := crypto.GenerateSecp256k1Key(rand.Reader)
assert.NoError(t, err)
convertedKey, err := ecdsaprysm.ConvertFromInterfacePrivKey(priv)
assert.NoError(t, err)
localNode := enode.NewLocalNode(db, convertedKey)
retrievedSubnets, err := computeSubscribedSubnets(localNode.ID(), 1000)
assert.NoError(t, err)
assert.Equal(t, retrievedSubnets[0]+1, retrievedSubnets[1])
}
func TestInitializePersistentSubnets(t *testing.T) {
cache.SubnetIDs.EmptyAllCaches()
defer cache.SubnetIDs.EmptyAllCaches()
db, err := enode.OpenDB("")
assert.NoError(t, err)
defer db.Close()
priv, _, err := crypto.GenerateSecp256k1Key(rand.Reader)
assert.NoError(t, err)
convertedKey, err := ecdsaprysm.ConvertFromInterfacePrivKey(priv)
assert.NoError(t, err)
localNode := enode.NewLocalNode(db, convertedKey)
assert.NoError(t, initializePersistentSubnets(localNode.ID(), 10000))
subs, ok, expTime := cache.SubnetIDs.GetPersistentSubnets()
assert.Equal(t, true, ok)
assert.Equal(t, 2, len(subs))
assert.Equal(t, true, expTime.After(time.Now()))
}

View File

@@ -30,7 +30,6 @@ go_library(
"//consensus-types/primitives:go_default_library",
"//consensus-types/validator:go_default_library",
"//crypto/bls:go_default_library",
"//crypto/rand:go_default_library",
"//encoding/bytesutil:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",

View File

@@ -22,7 +22,6 @@ import (
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/consensus-types/validator"
"github.com/prysmaticlabs/prysm/v4/crypto/bls"
"github.com/prysmaticlabs/prysm/v4/crypto/rand"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/runtime/version"
@@ -310,46 +309,6 @@ func (s *Service) AggregatedSigAndAggregationBits(
return aggregatedSig, bits, nil
}
// AssignValidatorToSubnet checks the status and pubkey of a particular validator
// to discern whether persistent subnets need to be registered for them.
func AssignValidatorToSubnet(pubkey []byte, status validator.Status) {
if status != validator.Active {
return
}
assignValidatorToSubnet(pubkey)
}
// AssignValidatorToSubnetProto checks the status and pubkey of a particular validator
// to discern whether persistent subnets need to be registered for them.
//
// It has a Proto suffix because the status is a protobuf type.
func AssignValidatorToSubnetProto(pubkey []byte, status ethpb.ValidatorStatus) {
if status != ethpb.ValidatorStatus_ACTIVE && status != ethpb.ValidatorStatus_EXITING {
return
}
assignValidatorToSubnet(pubkey)
}
func assignValidatorToSubnet(pubkey []byte) {
_, ok, expTime := cache.SubnetIDs.GetPersistentSubnets(pubkey)
if ok && expTime.After(prysmTime.Now()) {
return
}
epochDuration := time.Duration(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().SecondsPerSlot))
var assignedIdxs []uint64
randGen := rand.NewGenerator()
for i := uint64(0); i < params.BeaconConfig().RandomSubnetsPerValidator; i++ {
assignedIdx := randGen.Intn(int(params.BeaconNetworkConfig().AttestationSubnetCount))
assignedIdxs = append(assignedIdxs, uint64(assignedIdx))
}
assignedDuration := uint64(randGen.Intn(int(params.BeaconConfig().EpochsPerRandomSubnetSubscription)))
assignedDuration += params.BeaconConfig().EpochsPerRandomSubnetSubscription
totalDuration := epochDuration * time.Duration(assignedDuration)
cache.SubnetIDs.AddPersistentCommittee(pubkey, assignedIdxs, totalDuration*time.Second)
}
// GetAttestationData requests that the beacon node produces attestation data for
// the requested committee index and slot based on the nodes current head.
func (s *Service) GetAttestationData(

View File

@@ -172,7 +172,7 @@ func TestGetSpec(t *testing.T) {
data, ok := resp.Data.(map[string]interface{})
require.Equal(t, true, ok)
assert.Equal(t, 113, len(data))
assert.Equal(t, 118, len(data))
for k, v := range data {
switch k {
case "CONFIG_NAME":
@@ -418,6 +418,16 @@ func TestGetSpec(t *testing.T) {
case "MAX_REQUEST_LIGHT_CLIENT_UPDATES":
assert.Equal(t, "128", v)
case "SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY":
case "NODE_ID_BITS":
assert.Equal(t, "256", v)
case "ATTESTATION_SUBNET_EXTRA_BITS":
assert.Equal(t, "0", v)
case "ATTESTATION_SUBNET_PREFIX_BITS":
assert.Equal(t, "6", v)
case "SUBNETS_PER_NODE":
assert.Equal(t, "2", v)
case "EPOCHS_PER_SUBNET_SUBSCRIPTION":
assert.Equal(t, "256", v)
default:
t.Errorf("Incorrect key: %s", k)
}

View File

@@ -381,15 +381,6 @@ func (s *Server) SubmitBeaconCommitteeSubscription(w http.ResponseWriter, r *htt
cache.SubnetIDs.AddAggregatorSubnetID(sub.Slot, subnet)
}
}
for _, val := range validators {
valStatus, err := rpchelpers.ValidatorStatus(val, currEpoch)
if err != nil {
http2.HandleError(w, "Could not retrieve validator status: "+err.Error(), http.StatusInternalServerError)
return
}
pubkey := val.PublicKey()
core.AssignValidatorToSubnet(pubkey[:], valStatus)
}
}
// GetAttestationData requests that the beacon node produces attestation data for

View File

@@ -737,25 +737,6 @@ func TestSubmitBeaconCommitteeSubscription(t *testing.T) {
require.Equal(t, 1, len(subnets))
assert.Equal(t, uint64(5), subnets[0])
})
t.Run("validators assigned to subnets", func(t *testing.T) {
cache.SubnetIDs.EmptyAllCaches()
var body bytes.Buffer
_, err := body.WriteString(multipleBeaconCommitteeContribution2)
require.NoError(t, err)
request := httptest.NewRequest(http.MethodPost, "http://example.com", &body)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.SubmitBeaconCommitteeSubscription(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
subnets, ok, _ := cache.SubnetIDs.GetPersistentSubnets(pubkeys[1])
require.Equal(t, true, ok, "subnet for validator 1 not found")
assert.Equal(t, 1, len(subnets))
subnets, ok, _ = cache.SubnetIDs.GetPersistentSubnets(pubkeys[2])
require.Equal(t, true, ok, "subnet for validator 2 not found")
assert.Equal(t, 1, len(subnets))
})
t.Run("no body", func(t *testing.T) {
request := httptest.NewRequest(http.MethodPost, "http://example.com", nil)
writer := httptest.NewRecorder()

View File

@@ -227,9 +227,6 @@ func (vs *Server) duties(ctx context.Context, req *ethpb.DutiesRequest) (*ethpb.
validatorAssignments = append(validatorAssignments, assignment)
nextValidatorAssignments = append(nextValidatorAssignments, nextAssignment)
// Assign relevant validator to subnet.
core.AssignValidatorToSubnetProto(pubKey, assignment.Status)
core.AssignValidatorToSubnetProto(pubKey, nextAssignment.Status)
}
// Prune payload ID cache for any slots before request slot.
vs.ProposerSlotIndexCache.PrunePayloadIDs(epochStartSlot)
@@ -244,6 +241,5 @@ func (vs *Server) duties(ctx context.Context, req *ethpb.DutiesRequest) (*ethpb.
// AssignValidatorToSubnet checks the status and pubkey of a particular validator
// to discern whether persistent subnets need to be registered for them.
func (vs *Server) AssignValidatorToSubnet(_ context.Context, req *ethpb.AssignValidatorToSubnetRequest) (*emptypb.Empty, error) {
core.AssignValidatorToSubnetProto(req.PublicKey, req.Status)
return &emptypb.Empty{}, nil
}

View File

@@ -17,7 +17,6 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/transition"
mockExecution "github.com/prysmaticlabs/prysm/v4/beacon-chain/execution/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/core"
mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params"
@@ -604,21 +603,6 @@ func TestStreamDuties_OK_ChainReorg(t *testing.T) {
cancel()
}
func TestAssignValidatorToSubnet(t *testing.T) {
k := pubKey(3)
core.AssignValidatorToSubnetProto(k, ethpb.ValidatorStatus_ACTIVE)
coms, ok, exp := cache.SubnetIDs.GetPersistentSubnets(k)
require.Equal(t, true, ok, "No cache entry found for validator")
assert.Equal(t, params.BeaconConfig().RandomSubnetsPerValidator, uint64(len(coms)))
epochDuration := time.Duration(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().SecondsPerSlot))
totalTime := time.Duration(params.BeaconConfig().EpochsPerRandomSubnetSubscription) * epochDuration * time.Second
receivedTime := time.Until(exp.Round(time.Second))
if receivedTime < totalTime {
t.Fatalf("Expiration time of %f was less than expected duration of %f ", receivedTime.Seconds(), totalTime.Seconds())
}
}
func BenchmarkCommitteeAssignment(b *testing.B) {
genesis := util.NewBeaconBlock()

View File

@@ -225,6 +225,13 @@ type BeaconChainConfig struct {
// Values introduced in Deneb hard fork
MaxPerEpochActivationChurnLimit uint64 `yaml:"MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT" spec:"true"` // MaxPerEpochActivationChurnLimit is the maximum amount of churn allotted for validator activation.
// Values related to the new subnet backbone
EpochsPerSubnetSubscription uint64 `yaml:"EPOCHS_PER_SUBNET_SUBSCRIPTION" spec:"true"` // EpochsPerSubnetSubscription specifies the minimum duration a validator is connected to their subnet.
AttestationSubnetExtraBits uint64 `yaml:"ATTESTATION_SUBNET_EXTRA_BITS" spec:"true"` // AttestationSubnetExtraBits is the number of extra bits of a NodeId to use when mapping to a subscribed subnet.
AttestationSubnetPrefixBits uint64 `yaml:"ATTESTATION_SUBNET_PREFIX_BITS" spec:"true"` // AttestationSubnetPrefixBits is defined as (ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS).
SubnetsPerNode uint64 `yaml:"SUBNETS_PER_NODE" spec:"true"` // SubnetsPerNode is the number of long-lived subnets a beacon node should be subscribed to.
NodeIdBits uint64 `yaml:"NODE_ID_BITS" spec:"true"` // NodeIdBits defines the bit length of a node id.
}
// InitializeForkSchedule initializes the schedules forks baked into the config.

View File

@@ -209,6 +209,11 @@ func ConfigToYaml(cfg *BeaconChainConfig) []byte {
fmt.Sprintf("DEPOSIT_CONTRACT_ADDRESS: %s", cfg.DepositContractAddress),
fmt.Sprintf("DENEB_FORK_EPOCH: %d", cfg.DenebForkEpoch),
fmt.Sprintf("DENEB_FORK_VERSION: %#x", cfg.DenebForkVersion),
fmt.Sprintf("EPOCHS_PER_SUBNET_SUBSCRIPTION: %d", cfg.EpochsPerSubnetSubscription),
fmt.Sprintf("ATTESTATION_SUBNET_EXTRA_BITS: %d", cfg.AttestationSubnetExtraBits),
fmt.Sprintf("ATTESTATION_SUBNET_PREFIX_BITS: %d", cfg.AttestationSubnetPrefixBits),
fmt.Sprintf("SUBNETS_PER_NODE: %d", cfg.SubnetsPerNode),
fmt.Sprintf("NODE_ID_BITS: %d", cfg.NodeIdBits),
}
yamlFile := []byte(strings.Join(lines, "\n"))

View File

@@ -25,13 +25,10 @@ import (
var placeholderFields = []string{
"ATTESTATION_PROPAGATION_SLOT_RANGE",
"ATTESTATION_SUBNET_COUNT",
"ATTESTATION_SUBNET_EXTRA_BITS",
"ATTESTATION_SUBNET_PREFIX_BITS",
"EIP6110_FORK_EPOCH",
"EIP6110_FORK_VERSION",
"EIP7002_FORK_EPOCH",
"EIP7002_FORK_VERSION",
"EPOCHS_PER_SUBNET_SUBSCRIPTION",
"GOSSIP_MAX_SIZE",
"MAXIMUM_GOSSIP_CLOCK_DISPARITY",
"MAX_BLOBS_PER_BLOCK",
@@ -44,7 +41,6 @@ var placeholderFields = []string{
"MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS",
"MIN_EPOCHS_FOR_BLOCK_REQUESTS",
"RESP_TIMEOUT",
"SUBNETS_PER_NODE",
"TTFB_TIMEOUT",
"UPDATE_TIMEOUT",
"WHISK_EPOCHS_PER_SHUFFLING_PHASE",

View File

@@ -274,6 +274,13 @@ var mainnetBeaconConfig = &BeaconChainConfig{
BlobsidecarSubnetCount: 6,
MaxPerEpochActivationChurnLimit: 8,
// Values related to the new subnet backbone
EpochsPerSubnetSubscription: 256,
AttestationSubnetExtraBits: 0,
AttestationSubnetPrefixBits: 6,
SubnetsPerNode: 2,
NodeIdBits: 256,
}
// MainnetTestConfig provides a version of the mainnet config that has a different name

View File

@@ -262,11 +262,7 @@ func createTestnetDir() (string, error) {
rawYaml = append(rawYaml, []byte(depContractStr)...)
rawYaml = append(rawYaml, params.NetworkConfigToYaml(params.BeaconNetworkConfig())...)
rawYaml = append(rawYaml, []byte("\nEPOCHS_PER_SUBNET_SUBSCRIPTION: 256\n")...)
rawYaml = append(rawYaml, []byte("\nMIN_EPOCHS_FOR_BLOCK_REQUESTS: 33024\n")...)
rawYaml = append(rawYaml, []byte("\nSUBNETS_PER_NODE: 2\n")...)
rawYaml = append(rawYaml, []byte("\nATTESTATION_SUBNET_EXTRA_BITS: 0\n")...)
rawYaml = append(rawYaml, []byte("\nATTESTATION_SUBNET_PREFIX_BITS: 6\n")...)
if err := file.MkdirAll(testNetDir); err != nil {
return "", err

View File

@@ -12,7 +12,7 @@ import (
"github.com/golang/mock/gomock"
"github.com/golang/protobuf/ptypes/empty"
"github.com/prysmaticlabs/prysm/v4/io/logs/mock"
"github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
eth "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
pb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/testing/require"
validatormock "github.com/prysmaticlabs/prysm/v4/testing/validator-mock"