diff --git a/genesis/bootstrappers.go b/genesis/bootstrappers.go index 4aec33f9c3d9..d261050a8d19 100644 --- a/genesis/bootstrappers.go +++ b/genesis/bootstrappers.go @@ -36,10 +36,17 @@ type Bootstrapper struct { IP ips.IPDesc `json:"ip"` } -// SampleBootstrappers returns the some beacons this node should connect to -func SampleBootstrappers(networkID uint32, count int) []Bootstrapper { +// GetBootstrappers returns all the default bootstrappers for the provided +// network +func GetBootstrappers(networkID uint32) []Bootstrapper { networkName := constants.NetworkIDToNetworkName[networkID] - bootstrappers := bootstrappersPerNetwork[networkName] + return bootstrappersPerNetwork[networkName] +} + +// SampleBootstrappers returns some bootstrappers this node can connect to when +// joining the provided network +func SampleBootstrappers(networkID uint32, count int) []Bootstrapper { + bootstrappers := GetBootstrappers(networkID) count = math.Min(count, len(bootstrappers)) s := sampler.NewUniform() diff --git a/network/network.go b/network/network.go index 3f89e0ea00ef..765d35fd8f59 100644 --- a/network/network.go +++ b/network/network.go @@ -23,6 +23,7 @@ import ( "golang.org/x/exp/maps" "github.com/ava-labs/avalanchego/api/health" + "github.com/ava-labs/avalanchego/genesis" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/message" "github.com/ava-labs/avalanchego/network/dialer" @@ -685,20 +686,14 @@ func (n *network) Peers(peerID ids.NodeID) ([]ips.ClaimedIPPort, error) { return nil, nil } - // We select a random sample of validators to gossip to avoid starving out a - // validator from being gossiped for an extended period of time. - s := sampler.NewUniform() - s.Initialize(uint64(len(unknownValidators))) + var bootstrapperIDs set.Set[ids.NodeID] + for _, bootstrapper := range genesis.GetBootstrappers(n.config.NetworkID) { + bootstrapperIDs.Add(bootstrapper.ID) + } // Calculate the unknown information we need to send to this peer. validatorIPs := make([]ips.ClaimedIPPort, 0, int(n.config.PeerListNumValidatorIPs)) - for i := 0; i < len(unknownValidators) && len(validatorIPs) < int(n.config.PeerListNumValidatorIPs); i++ { - drawn, err := s.Next() - if err != nil { - return nil, err - } - - validator := unknownValidators[drawn] + tryAddValidator := func(validator peer.ValidatorID) { n.peersLock.RLock() _, isConnected := n.connectedPeers.GetByID(validator.NodeID) peerIP := n.peerIPs[validator.NodeID] @@ -708,7 +703,7 @@ func (n *network) Peers(peerID ids.NodeID) ([]ips.ClaimedIPPort, error) { "unable to find validator in connected peers", zap.Stringer("nodeID", validator.NodeID), ) - continue + return } // Note: peerIP isn't used directly here because the TxID may be @@ -723,6 +718,32 @@ func (n *network) Peers(peerID ids.NodeID) ([]ips.ClaimedIPPort, error) { }, ) } + for _, validator := range unknownValidators { + if !bootstrapperIDs.Contains(validator.NodeID) { + continue + } + + tryAddValidator(validator) + } + + // We select a random sample of validators to gossip to avoid starving out a + // validator from being gossiped for an extended period of time. + s := sampler.NewUniform() + s.Initialize(uint64(len(unknownValidators))) + + for i := 0; i < len(unknownValidators) && len(validatorIPs) < int(n.config.PeerListNumValidatorIPs); i++ { + drawn, err := s.Next() + if err != nil { + return nil, err + } + + validator := unknownValidators[drawn] + if bootstrapperIDs.Contains(validator.NodeID) { + continue + } + + tryAddValidator(validator) + } return validatorIPs, nil } diff --git a/utils/constants/networking.go b/utils/constants/networking.go index a9417eac37c9..8638d96c6ba7 100644 --- a/utils/constants/networking.go +++ b/utils/constants/networking.go @@ -27,7 +27,7 @@ const ( MaxContainersLen = int(4 * DefaultMaxMessageSize / 5) - DefaultNetworkPeerListNumValidatorIPs = 15 + DefaultNetworkPeerListNumValidatorIPs = 30 DefaultNetworkPeerListValidatorGossipSize = 20 DefaultNetworkPeerListNonValidatorGossipSize = 0 DefaultNetworkPeerListPeersGossipSize = 10