mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 21:38:05 -05:00
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:
10
beacon-chain/cache/subnet_ids.go
vendored
10
beacon-chain/cache/subnet_ids.go
vendored
@@ -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
|
||||
|
||||
19
beacon-chain/cache/subnet_ids_test.go
vendored
19
beacon-chain/cache/subnet_ids_test.go
vendored
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
},
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()))
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user